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 document_colors;
   21mod editor_settings;
   22mod element;
   23mod folding_ranges;
   24mod git;
   25mod highlight_matching_bracket;
   26mod hover_links;
   27pub mod hover_popover;
   28mod indent_guides;
   29mod inlays;
   30pub mod items;
   31mod jsx_tag_auto_close;
   32mod linked_editing_ranges;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod semantic_tokens;
   41mod split;
   42pub mod split_editor_view;
   43pub mod tasks;
   44
   45#[cfg(test)]
   46mod code_completion_tests;
   47#[cfg(test)]
   48mod edit_prediction_tests;
   49#[cfg(test)]
   50mod editor_tests;
   51mod signature_help;
   52#[cfg(any(test, feature = "test-support"))]
   53pub mod test;
   54
   55pub(crate) use actions::*;
   56pub use display_map::{
   57    ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder, HighlightKey,
   58    SemanticTokenHighlight,
   59};
   60pub use edit_prediction_types::Direction;
   61pub use editor_settings::{
   62    CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode,
   63    EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings,
   64    ShowMinimap,
   65};
   66pub use element::{
   67    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   68    render_breadcrumb_text,
   69};
   70pub use git::blame::BlameRenderer;
   71pub use hover_popover::hover_markdown_style;
   72pub use inlays::Inlay;
   73pub use items::MAX_TAB_TITLE_LEN;
   74pub use lsp::CompletionContext;
   75pub use lsp_ext::lsp_tasks;
   76pub use multi_buffer::{
   77    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   78    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   79    ToPoint,
   80};
   81pub use split::{SplittableEditor, ToggleSplitDiff};
   82pub use split_editor_view::SplitEditorView;
   83pub use text::Bias;
   84
   85use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   86use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   87use anyhow::{Context as _, Result, anyhow, bail};
   88use blink_manager::BlinkManager;
   89use buffer_diff::DiffHunkStatus;
   90use client::{Collaborator, ParticipantIndex, parse_zed_link};
   91use clock::ReplicaId;
   92use code_context_menus::{
   93    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   94    CompletionsMenu, ContextMenuOrigin,
   95};
   96use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   97use convert_case::{Case, Casing};
   98use dap::TelemetrySpawnLocation;
   99use display_map::*;
  100use document_colors::LspColorData;
  101use edit_prediction_types::{
  102    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionDiscardReason,
  103    EditPredictionGranularity, SuggestionDisplayType,
  104};
  105use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
  106use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
  107use futures::{
  108    FutureExt,
  109    future::{self, Shared, join},
  110};
  111use fuzzy::{StringMatch, StringMatchCandidate};
  112use git::blame::{GitBlame, GlobalBlameRenderer};
  113use gpui::{
  114    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  115    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  116    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  117    Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  118    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  119    Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled, Subscription, Task,
  120    TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
  121    UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*,
  122    pulsating_between, px, relative, size,
  123};
  124use hover_links::{HoverLink, HoveredLinkState, find_file};
  125use hover_popover::{HoverState, hide_hover};
  126use indent_guides::ActiveIndentGuidesState;
  127use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  128use itertools::{Either, Itertools};
  129use language::{
  130    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  131    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  132    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  133    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  134    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  135    TreeSitterOptions, WordsQuery,
  136    language_settings::{
  137        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  138        all_language_settings, language_settings,
  139    },
  140    point_from_lsp, point_to_lsp, text_diff_with_options,
  141};
  142use linked_editing_ranges::refresh_linked_ranges;
  143use lsp::{
  144    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  145    LanguageServerId,
  146};
  147use markdown::Markdown;
  148use mouse_context_menu::MouseContextMenu;
  149use movement::TextLayoutDetails;
  150use multi_buffer::{
  151    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  152};
  153use parking_lot::Mutex;
  154use persistence::DB;
  155use project::{
  156    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  157    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  158    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  159    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  160    debugger::{
  161        breakpoint_store::{
  162            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  163            BreakpointStore, BreakpointStoreEvent,
  164        },
  165        session::{Session, SessionEvent},
  166    },
  167    git_store::GitStoreEvent,
  168    lsp_store::{
  169        BufferSemanticTokens, CacheInlayHints, CompletionDocumentation, FormatTrigger,
  170        LspFormatTarget, OpenLspBufferHandle, RefreshForServer,
  171    },
  172    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  173};
  174use rand::seq::SliceRandom;
  175use regex::Regex;
  176use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  177use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, SharedScrollAnchor};
  178use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  179use serde::{Deserialize, Serialize};
  180use settings::{
  181    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  182    update_settings_file,
  183};
  184use smallvec::{SmallVec, smallvec};
  185use snippet::Snippet;
  186use std::{
  187    any::{Any, TypeId},
  188    borrow::Cow,
  189    cell::{OnceCell, RefCell},
  190    cmp::{self, Ordering, Reverse},
  191    collections::hash_map,
  192    iter::{self, Peekable},
  193    mem,
  194    num::NonZeroU32,
  195    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  196    path::{Path, PathBuf},
  197    rc::Rc,
  198    sync::Arc,
  199    time::{Duration, Instant},
  200};
  201use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  202use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  203use theme::{
  204    AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
  205    ThemeSettings, observe_buffer_font_size_adjustment,
  206};
  207use ui::{
  208    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  209    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  210};
  211use ui_input::ErasedEditor;
  212use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  213use workspace::{
  214    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  215    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  216    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  217    item::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  218    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  219    searchable::{CollapseDirection, SearchEvent},
  220};
  221use zed_actions::editor::{MoveDown, MoveUp};
  222
  223use crate::{
  224    code_context_menus::CompletionsMenuSource,
  225    editor_settings::MultiCursorModifier,
  226    hover_links::{find_url, find_url_from_range},
  227    inlays::{
  228        InlineValueCache,
  229        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  230    },
  231    scroll::{ScrollOffset, ScrollPixelOffset},
  232    selections_collection::resolve_selections_wrapping_blocks,
  233    semantic_tokens::SemanticTokenState,
  234    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  235};
  236
  237pub const FILE_HEADER_HEIGHT: u32 = 2;
  238pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  239const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  240const MAX_LINE_LEN: usize = 1024;
  241const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  242const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  243pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  244#[doc(hidden)]
  245pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  246pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  247
  248pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  249pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  250pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  251pub const LSP_REQUEST_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  252
  253pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  254pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  255pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  256
  257pub type RenderDiffHunkControlsFn = Arc<
  258    dyn Fn(
  259        u32,
  260        &DiffHunkStatus,
  261        Range<Anchor>,
  262        bool,
  263        Pixels,
  264        &Entity<Editor>,
  265        &mut Window,
  266        &mut App,
  267    ) -> AnyElement,
  268>;
  269
  270enum ReportEditorEvent {
  271    Saved { auto_saved: bool },
  272    EditorOpened,
  273    Closed,
  274}
  275
  276impl ReportEditorEvent {
  277    pub fn event_type(&self) -> &'static str {
  278        match self {
  279            Self::Saved { .. } => "Editor Saved",
  280            Self::EditorOpened => "Editor Opened",
  281            Self::Closed => "Editor Closed",
  282        }
  283    }
  284}
  285
  286pub enum ActiveDebugLine {}
  287pub enum DebugStackFrameLine {}
  288
  289pub enum ConflictsOuter {}
  290pub enum ConflictsOurs {}
  291pub enum ConflictsTheirs {}
  292pub enum ConflictsOursMarker {}
  293pub enum ConflictsTheirsMarker {}
  294
  295pub struct HunkAddedColor;
  296pub struct HunkRemovedColor;
  297
  298#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  299pub enum Navigated {
  300    Yes,
  301    No,
  302}
  303
  304impl Navigated {
  305    pub fn from_bool(yes: bool) -> Navigated {
  306        if yes { Navigated::Yes } else { Navigated::No }
  307    }
  308}
  309
  310#[derive(Debug, Clone, PartialEq, Eq)]
  311enum DisplayDiffHunk {
  312    Folded {
  313        display_row: DisplayRow,
  314    },
  315    Unfolded {
  316        is_created_file: bool,
  317        diff_base_byte_range: Range<usize>,
  318        display_row_range: Range<DisplayRow>,
  319        multi_buffer_range: Range<Anchor>,
  320        status: DiffHunkStatus,
  321        word_diffs: Vec<Range<MultiBufferOffset>>,
  322    },
  323}
  324
  325pub enum HideMouseCursorOrigin {
  326    TypingAction,
  327    MovementAction,
  328}
  329
  330pub fn init(cx: &mut App) {
  331    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  332    cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text));
  333
  334    workspace::register_project_item::<Editor>(cx);
  335    workspace::FollowableViewRegistry::register::<Editor>(cx);
  336    workspace::register_serializable_item::<Editor>(cx);
  337
  338    cx.observe_new(
  339        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  340            workspace.register_action(Editor::new_file);
  341            workspace.register_action(Editor::new_file_split);
  342            workspace.register_action(Editor::new_file_vertical);
  343            workspace.register_action(Editor::new_file_horizontal);
  344            workspace.register_action(Editor::cancel_language_server_work);
  345            workspace.register_action(Editor::toggle_focus);
  346        },
  347    )
  348    .detach();
  349
  350    cx.on_action(move |_: &workspace::NewFile, cx| {
  351        let app_state = workspace::AppState::global(cx);
  352        if let Some(app_state) = app_state.upgrade() {
  353            workspace::open_new(
  354                Default::default(),
  355                app_state,
  356                cx,
  357                |workspace, window, cx| {
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    })
  364    .on_action(move |_: &workspace::NewWindow, cx| {
  365        let app_state = workspace::AppState::global(cx);
  366        if let Some(app_state) = app_state.upgrade() {
  367            workspace::open_new(
  368                Default::default(),
  369                app_state,
  370                cx,
  371                |workspace, window, cx| {
  372                    cx.activate(true);
  373                    Editor::new_file(workspace, &Default::default(), window, cx)
  374                },
  375            )
  376            .detach();
  377        }
  378    });
  379    _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| {
  380        Arc::new(ErasedEditorImpl(
  381            cx.new(|cx| Editor::single_line(window, cx)),
  382        )) as Arc<dyn ErasedEditor>
  383    });
  384    _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);
  385}
  386
  387pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  388    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  389}
  390
  391pub trait DiagnosticRenderer {
  392    fn render_group(
  393        &self,
  394        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  395        buffer_id: BufferId,
  396        snapshot: EditorSnapshot,
  397        editor: WeakEntity<Editor>,
  398        language_registry: Option<Arc<LanguageRegistry>>,
  399        cx: &mut App,
  400    ) -> Vec<BlockProperties<Anchor>>;
  401
  402    fn render_hover(
  403        &self,
  404        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  405        range: Range<Point>,
  406        buffer_id: BufferId,
  407        language_registry: Option<Arc<LanguageRegistry>>,
  408        cx: &mut App,
  409    ) -> Option<Entity<markdown::Markdown>>;
  410
  411    fn open_link(
  412        &self,
  413        editor: &mut Editor,
  414        link: SharedString,
  415        window: &mut Window,
  416        cx: &mut Context<Editor>,
  417    );
  418}
  419
  420pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  421
  422impl GlobalDiagnosticRenderer {
  423    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  424        cx.try_global::<Self>().map(|g| g.0.clone())
  425    }
  426}
  427
  428impl gpui::Global for GlobalDiagnosticRenderer {}
  429pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  430    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  431}
  432
  433pub struct SearchWithinRange;
  434
  435trait InvalidationRegion {
  436    fn ranges(&self) -> &[Range<Anchor>];
  437}
  438
  439#[derive(Clone, Debug, PartialEq)]
  440pub enum SelectPhase {
  441    Begin {
  442        position: DisplayPoint,
  443        add: bool,
  444        click_count: usize,
  445    },
  446    BeginColumnar {
  447        position: DisplayPoint,
  448        reset: bool,
  449        mode: ColumnarMode,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug, PartialEq)]
  465pub enum ColumnarMode {
  466    FromMouse,
  467    FromSelection,
  468}
  469
  470#[derive(Clone, Debug)]
  471pub enum SelectMode {
  472    Character,
  473    Word(Range<Anchor>),
  474    Line(Range<Anchor>),
  475    All,
  476}
  477
  478#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  479pub enum SizingBehavior {
  480    /// The editor will layout itself using `size_full` and will include the vertical
  481    /// scroll margin as requested by user settings.
  482    #[default]
  483    Default,
  484    /// The editor will layout itself using `size_full`, but will not have any
  485    /// vertical overscroll.
  486    ExcludeOverscrollMargin,
  487    /// The editor will request a vertical size according to its content and will be
  488    /// layouted without a vertical scroll margin.
  489    SizeByContent,
  490}
  491
  492#[derive(Clone, PartialEq, Eq, Debug)]
  493pub enum EditorMode {
  494    SingleLine,
  495    AutoHeight {
  496        min_lines: usize,
  497        max_lines: Option<usize>,
  498    },
  499    Full {
  500        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  501        scale_ui_elements_with_buffer_font_size: bool,
  502        /// When set to `true`, the editor will render a background for the active line.
  503        show_active_line_background: bool,
  504        /// Determines the sizing behavior for this editor
  505        sizing_behavior: SizingBehavior,
  506    },
  507    Minimap {
  508        parent: WeakEntity<Editor>,
  509    },
  510}
  511
  512impl EditorMode {
  513    pub fn full() -> Self {
  514        Self::Full {
  515            scale_ui_elements_with_buffer_font_size: true,
  516            show_active_line_background: true,
  517            sizing_behavior: SizingBehavior::Default,
  518        }
  519    }
  520
  521    #[inline]
  522    pub fn is_full(&self) -> bool {
  523        matches!(self, Self::Full { .. })
  524    }
  525
  526    #[inline]
  527    pub fn is_single_line(&self) -> bool {
  528        matches!(self, Self::SingleLine { .. })
  529    }
  530
  531    #[inline]
  532    fn is_minimap(&self) -> bool {
  533        matches!(self, Self::Minimap { .. })
  534    }
  535}
  536
  537#[derive(Copy, Clone, Debug)]
  538pub enum SoftWrap {
  539    /// Prefer not to wrap at all.
  540    ///
  541    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  542    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  543    GitDiff,
  544    /// Prefer a single line generally, unless an overly long line is encountered.
  545    None,
  546    /// Soft wrap lines that exceed the editor width.
  547    EditorWidth,
  548    /// Soft wrap lines at the preferred line length.
  549    Column(u32),
  550    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  551    Bounded(u32),
  552}
  553
  554#[derive(Clone)]
  555pub struct EditorStyle {
  556    pub background: Hsla,
  557    pub border: Hsla,
  558    pub local_player: PlayerColor,
  559    pub text: TextStyle,
  560    pub scrollbar_width: Pixels,
  561    pub syntax: Arc<SyntaxTheme>,
  562    pub status: StatusColors,
  563    pub inlay_hints_style: HighlightStyle,
  564    pub edit_prediction_styles: EditPredictionStyles,
  565    pub unnecessary_code_fade: f32,
  566    pub show_underlines: bool,
  567}
  568
  569impl Default for EditorStyle {
  570    fn default() -> Self {
  571        Self {
  572            background: Hsla::default(),
  573            border: Hsla::default(),
  574            local_player: PlayerColor::default(),
  575            text: TextStyle::default(),
  576            scrollbar_width: Pixels::default(),
  577            syntax: Default::default(),
  578            // HACK: Status colors don't have a real default.
  579            // We should look into removing the status colors from the editor
  580            // style and retrieve them directly from the theme.
  581            status: StatusColors::dark(),
  582            inlay_hints_style: HighlightStyle::default(),
  583            edit_prediction_styles: EditPredictionStyles {
  584                insertion: HighlightStyle::default(),
  585                whitespace: HighlightStyle::default(),
  586            },
  587            unnecessary_code_fade: Default::default(),
  588            show_underlines: true,
  589        }
  590    }
  591}
  592
  593pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  594    let show_background = language_settings::language_settings(None, None, cx)
  595        .inlay_hints
  596        .show_background;
  597
  598    let mut style = cx.theme().syntax().get("hint");
  599
  600    if style.color.is_none() {
  601        style.color = Some(cx.theme().status().hint);
  602    }
  603
  604    if !show_background {
  605        style.background_color = None;
  606        return style;
  607    }
  608
  609    if style.background_color.is_none() {
  610        style.background_color = Some(cx.theme().status().hint_background);
  611    }
  612
  613    style
  614}
  615
  616pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  617    EditPredictionStyles {
  618        insertion: HighlightStyle {
  619            color: Some(cx.theme().status().predictive),
  620            ..HighlightStyle::default()
  621        },
  622        whitespace: HighlightStyle {
  623            background_color: Some(cx.theme().status().created_background),
  624            ..HighlightStyle::default()
  625        },
  626    }
  627}
  628
  629type CompletionId = usize;
  630
  631pub(crate) enum EditDisplayMode {
  632    TabAccept,
  633    DiffPopover,
  634    Inline,
  635}
  636
  637enum EditPrediction {
  638    Edit {
  639        edits: Vec<(Range<Anchor>, Arc<str>)>,
  640        /// Predicted cursor position as (anchor, offset_from_anchor).
  641        /// The anchor is in multibuffer coordinates; after applying edits,
  642        /// resolve the anchor and add the offset to get the final cursor position.
  643        cursor_position: Option<(Anchor, usize)>,
  644        edit_preview: Option<EditPreview>,
  645        display_mode: EditDisplayMode,
  646        snapshot: BufferSnapshot,
  647    },
  648    /// Move to a specific location in the active editor
  649    MoveWithin {
  650        target: Anchor,
  651        snapshot: BufferSnapshot,
  652    },
  653    /// Move to a specific location in a different editor (not the active one)
  654    MoveOutside {
  655        target: language::Anchor,
  656        snapshot: BufferSnapshot,
  657    },
  658}
  659
  660struct EditPredictionState {
  661    inlay_ids: Vec<InlayId>,
  662    completion: EditPrediction,
  663    completion_id: Option<SharedString>,
  664    invalidation_range: Option<Range<Anchor>>,
  665}
  666
  667enum EditPredictionSettings {
  668    Disabled,
  669    Enabled {
  670        show_in_menu: bool,
  671        preview_requires_modifier: bool,
  672    },
  673}
  674
  675#[derive(Debug, Clone)]
  676struct InlineDiagnostic {
  677    message: SharedString,
  678    group_id: usize,
  679    is_primary: bool,
  680    start: Point,
  681    severity: lsp::DiagnosticSeverity,
  682}
  683
  684pub enum MenuEditPredictionsPolicy {
  685    Never,
  686    ByProvider,
  687}
  688
  689pub enum EditPredictionPreview {
  690    /// Modifier is not pressed
  691    Inactive { released_too_fast: bool },
  692    /// Modifier pressed
  693    Active {
  694        since: Instant,
  695        previous_scroll_position: Option<SharedScrollAnchor>,
  696    },
  697}
  698
  699impl EditPredictionPreview {
  700    pub fn released_too_fast(&self) -> bool {
  701        match self {
  702            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  703            EditPredictionPreview::Active { .. } => false,
  704        }
  705    }
  706
  707    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<SharedScrollAnchor>) {
  708        if let EditPredictionPreview::Active {
  709            previous_scroll_position,
  710            ..
  711        } = self
  712        {
  713            *previous_scroll_position = scroll_position;
  714        }
  715    }
  716}
  717
  718pub struct ContextMenuOptions {
  719    pub min_entries_visible: usize,
  720    pub max_entries_visible: usize,
  721    pub placement: Option<ContextMenuPlacement>,
  722}
  723
  724#[derive(Debug, Clone, PartialEq, Eq)]
  725pub enum ContextMenuPlacement {
  726    Above,
  727    Below,
  728}
  729
  730#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  731struct EditorActionId(usize);
  732
  733impl EditorActionId {
  734    pub fn post_inc(&mut self) -> Self {
  735        let answer = self.0;
  736
  737        *self = Self(answer + 1);
  738
  739        Self(answer)
  740    }
  741}
  742
  743// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  744// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  745
  746type BackgroundHighlight = (
  747    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  748    Arc<[Range<Anchor>]>,
  749);
  750type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  751
  752#[derive(Default)]
  753struct ScrollbarMarkerState {
  754    scrollbar_size: Size<Pixels>,
  755    dirty: bool,
  756    markers: Arc<[PaintQuad]>,
  757    pending_refresh: Option<Task<Result<()>>>,
  758}
  759
  760impl ScrollbarMarkerState {
  761    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  762        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  763    }
  764}
  765
  766#[derive(Clone, Copy, PartialEq, Eq)]
  767pub enum MinimapVisibility {
  768    Disabled,
  769    Enabled {
  770        /// The configuration currently present in the users settings.
  771        setting_configuration: bool,
  772        /// Whether to override the currently set visibility from the users setting.
  773        toggle_override: bool,
  774    },
  775}
  776
  777impl MinimapVisibility {
  778    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  779        if mode.is_full() {
  780            Self::Enabled {
  781                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  782                toggle_override: false,
  783            }
  784        } else {
  785            Self::Disabled
  786        }
  787    }
  788
  789    fn hidden(&self) -> Self {
  790        match *self {
  791            Self::Enabled {
  792                setting_configuration,
  793                ..
  794            } => Self::Enabled {
  795                setting_configuration,
  796                toggle_override: setting_configuration,
  797            },
  798            Self::Disabled => Self::Disabled,
  799        }
  800    }
  801
  802    fn disabled(&self) -> bool {
  803        matches!(*self, Self::Disabled)
  804    }
  805
  806    fn settings_visibility(&self) -> bool {
  807        match *self {
  808            Self::Enabled {
  809                setting_configuration,
  810                ..
  811            } => setting_configuration,
  812            _ => false,
  813        }
  814    }
  815
  816    fn visible(&self) -> bool {
  817        match *self {
  818            Self::Enabled {
  819                setting_configuration,
  820                toggle_override,
  821            } => setting_configuration ^ toggle_override,
  822            _ => false,
  823        }
  824    }
  825
  826    fn toggle_visibility(&self) -> Self {
  827        match *self {
  828            Self::Enabled {
  829                toggle_override,
  830                setting_configuration,
  831            } => Self::Enabled {
  832                setting_configuration,
  833                toggle_override: !toggle_override,
  834            },
  835            Self::Disabled => Self::Disabled,
  836        }
  837    }
  838}
  839
  840#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  841pub enum BufferSerialization {
  842    All,
  843    NonDirtyBuffers,
  844}
  845
  846impl BufferSerialization {
  847    fn new(restore_unsaved_buffers: bool) -> Self {
  848        if restore_unsaved_buffers {
  849            Self::All
  850        } else {
  851            Self::NonDirtyBuffers
  852        }
  853    }
  854}
  855
  856#[derive(Clone, Debug)]
  857struct RunnableTasks {
  858    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  859    offset: multi_buffer::Anchor,
  860    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  861    column: u32,
  862    // Values of all named captures, including those starting with '_'
  863    extra_variables: HashMap<String, String>,
  864    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  865    context_range: Range<BufferOffset>,
  866}
  867
  868impl RunnableTasks {
  869    fn resolve<'a>(
  870        &'a self,
  871        cx: &'a task::TaskContext,
  872    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  873        self.templates.iter().filter_map(|(kind, template)| {
  874            template
  875                .resolve_task(&kind.to_id_base(), cx)
  876                .map(|task| (kind.clone(), task))
  877        })
  878    }
  879}
  880
  881#[derive(Clone)]
  882pub struct ResolvedTasks {
  883    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  884    position: Anchor,
  885}
  886
  887/// Addons allow storing per-editor state in other crates (e.g. Vim)
  888pub trait Addon: 'static {
  889    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  890
  891    fn render_buffer_header_controls(
  892        &self,
  893        _: &ExcerptInfo,
  894        _: &Window,
  895        _: &App,
  896    ) -> Option<AnyElement> {
  897        None
  898    }
  899
  900    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  901        None
  902    }
  903
  904    fn to_any(&self) -> &dyn std::any::Any;
  905
  906    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  907        None
  908    }
  909}
  910
  911struct ChangeLocation {
  912    current: Option<Vec<Anchor>>,
  913    original: Vec<Anchor>,
  914}
  915impl ChangeLocation {
  916    fn locations(&self) -> &[Anchor] {
  917        self.current.as_ref().unwrap_or(&self.original)
  918    }
  919}
  920
  921/// A set of caret positions, registered when the editor was edited.
  922pub struct ChangeList {
  923    changes: Vec<ChangeLocation>,
  924    /// Currently "selected" change.
  925    position: Option<usize>,
  926}
  927
  928impl ChangeList {
  929    pub fn new() -> Self {
  930        Self {
  931            changes: Vec::new(),
  932            position: None,
  933        }
  934    }
  935
  936    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  937    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  938    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  939        if self.changes.is_empty() {
  940            return None;
  941        }
  942
  943        let prev = self.position.unwrap_or(self.changes.len());
  944        let next = if direction == Direction::Prev {
  945            prev.saturating_sub(count)
  946        } else {
  947            (prev + count).min(self.changes.len() - 1)
  948        };
  949        self.position = Some(next);
  950        self.changes.get(next).map(|change| change.locations())
  951    }
  952
  953    /// Adds a new change to the list, resetting the change list position.
  954    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  955        self.position.take();
  956        if let Some(last) = self.changes.last_mut()
  957            && group
  958        {
  959            last.current = Some(new_positions)
  960        } else {
  961            self.changes.push(ChangeLocation {
  962                original: new_positions,
  963                current: None,
  964            });
  965        }
  966    }
  967
  968    pub fn last(&self) -> Option<&[Anchor]> {
  969        self.changes.last().map(|change| change.locations())
  970    }
  971
  972    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  973        self.changes.last().map(|change| change.original.as_slice())
  974    }
  975
  976    pub fn invert_last_group(&mut self) {
  977        if let Some(last) = self.changes.last_mut()
  978            && let Some(current) = last.current.as_mut()
  979        {
  980            mem::swap(&mut last.original, current);
  981        }
  982    }
  983}
  984
  985#[derive(Clone)]
  986struct InlineBlamePopoverState {
  987    scroll_handle: ScrollHandle,
  988    commit_message: Option<ParsedCommitMessage>,
  989    markdown: Entity<Markdown>,
  990}
  991
  992struct InlineBlamePopover {
  993    position: gpui::Point<Pixels>,
  994    hide_task: Option<Task<()>>,
  995    popover_bounds: Option<Bounds<Pixels>>,
  996    popover_state: InlineBlamePopoverState,
  997    keyboard_grace: bool,
  998}
  999
 1000enum SelectionDragState {
 1001    /// State when no drag related activity is detected.
 1002    None,
 1003    /// State when the mouse is down on a selection that is about to be dragged.
 1004    ReadyToDrag {
 1005        selection: Selection<Anchor>,
 1006        click_position: gpui::Point<Pixels>,
 1007        mouse_down_time: Instant,
 1008    },
 1009    /// State when the mouse is dragging the selection in the editor.
 1010    Dragging {
 1011        selection: Selection<Anchor>,
 1012        drop_cursor: Selection<Anchor>,
 1013        hide_drop_cursor: bool,
 1014    },
 1015}
 1016
 1017enum ColumnarSelectionState {
 1018    FromMouse {
 1019        selection_tail: Anchor,
 1020        display_point: Option<DisplayPoint>,
 1021    },
 1022    FromSelection {
 1023        selection_tail: Anchor,
 1024    },
 1025}
 1026
 1027/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1028/// a breakpoint on them.
 1029#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1030struct PhantomBreakpointIndicator {
 1031    display_row: DisplayRow,
 1032    /// There's a small debounce between hovering over the line and showing the indicator.
 1033    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1034    is_active: bool,
 1035    collides_with_existing_breakpoint: bool,
 1036}
 1037
 1038/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1039/// in diff view mode.
 1040#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1041pub(crate) struct PhantomDiffReviewIndicator {
 1042    /// The starting anchor of the selection (or the only row if not dragging).
 1043    pub start: Anchor,
 1044    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1045    pub end: Anchor,
 1046    /// There's a small debounce between hovering over the line and showing the indicator.
 1047    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1048    pub is_active: bool,
 1049}
 1050
 1051#[derive(Clone, Debug)]
 1052pub(crate) struct DiffReviewDragState {
 1053    pub start_anchor: Anchor,
 1054    pub current_anchor: Anchor,
 1055}
 1056
 1057impl DiffReviewDragState {
 1058    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1059        let start = self.start_anchor.to_display_point(snapshot).row();
 1060        let current = self.current_anchor.to_display_point(snapshot).row();
 1061
 1062        (start..=current).sorted()
 1063    }
 1064}
 1065
 1066/// Identifies a specific hunk in the diff buffer.
 1067/// Used as a key to group comments by their location.
 1068#[derive(Clone, Debug)]
 1069pub struct DiffHunkKey {
 1070    /// The file path (relative to worktree) this hunk belongs to.
 1071    pub file_path: Arc<util::rel_path::RelPath>,
 1072    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1073    pub hunk_start_anchor: Anchor,
 1074}
 1075
 1076/// A review comment stored locally before being sent to the Agent panel.
 1077#[derive(Clone)]
 1078pub struct StoredReviewComment {
 1079    /// Unique identifier for this comment (for edit/delete operations).
 1080    pub id: usize,
 1081    /// The comment text entered by the user.
 1082    pub comment: String,
 1083    /// Anchors for the code range being reviewed.
 1084    pub range: Range<Anchor>,
 1085    /// Timestamp when the comment was created (for chronological ordering).
 1086    pub created_at: Instant,
 1087    /// Whether this comment is currently being edited inline.
 1088    pub is_editing: bool,
 1089}
 1090
 1091impl StoredReviewComment {
 1092    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1093        Self {
 1094            id,
 1095            comment,
 1096            range: anchor_range,
 1097            created_at: Instant::now(),
 1098            is_editing: false,
 1099        }
 1100    }
 1101}
 1102
 1103/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1104pub(crate) struct DiffReviewOverlay {
 1105    pub anchor_range: Range<Anchor>,
 1106    /// The block ID for the overlay.
 1107    pub block_id: CustomBlockId,
 1108    /// The editor entity for the review input.
 1109    pub prompt_editor: Entity<Editor>,
 1110    /// The hunk key this overlay belongs to.
 1111    pub hunk_key: DiffHunkKey,
 1112    /// Whether the comments section is expanded.
 1113    pub comments_expanded: bool,
 1114    /// Editors for comments currently being edited inline.
 1115    /// Key: comment ID, Value: Editor entity for inline editing.
 1116    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1117    /// Subscriptions for inline edit editors' action handlers.
 1118    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1119    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1120    /// The current user's avatar URI for display in comment rows.
 1121    pub user_avatar_uri: Option<SharedUri>,
 1122    /// Subscription to keep the action handler alive.
 1123    _subscription: Subscription,
 1124}
 1125
 1126/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1127///
 1128/// See the [module level documentation](self) for more information.
 1129pub struct Editor {
 1130    focus_handle: FocusHandle,
 1131    last_focused_descendant: Option<WeakFocusHandle>,
 1132    /// The text buffer being edited
 1133    buffer: Entity<MultiBuffer>,
 1134    /// Map of how text in the buffer should be displayed.
 1135    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1136    pub display_map: Entity<DisplayMap>,
 1137    placeholder_display_map: Option<Entity<DisplayMap>>,
 1138    pub selections: SelectionsCollection,
 1139    pub scroll_manager: ScrollManager,
 1140    /// When inline assist editors are linked, they all render cursors because
 1141    /// typing enters text into each of them, even the ones that aren't focused.
 1142    pub(crate) show_cursor_when_unfocused: bool,
 1143    columnar_selection_state: Option<ColumnarSelectionState>,
 1144    add_selections_state: Option<AddSelectionsState>,
 1145    select_next_state: Option<SelectNextState>,
 1146    select_prev_state: Option<SelectNextState>,
 1147    selection_history: SelectionHistory,
 1148    defer_selection_effects: bool,
 1149    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1150    autoclose_regions: Vec<AutocloseRegion>,
 1151    snippet_stack: InvalidationStack<SnippetState>,
 1152    select_syntax_node_history: SelectSyntaxNodeHistory,
 1153    ime_transaction: Option<TransactionId>,
 1154    pub diagnostics_max_severity: DiagnosticSeverity,
 1155    active_diagnostics: ActiveDiagnostic,
 1156    show_inline_diagnostics: bool,
 1157    inline_diagnostics_update: Task<()>,
 1158    inline_diagnostics_enabled: bool,
 1159    diagnostics_enabled: bool,
 1160    word_completions_enabled: bool,
 1161    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1162    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1163    hard_wrap: Option<usize>,
 1164    project: Option<Entity<Project>>,
 1165    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1166    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1167    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1168    blink_manager: Entity<BlinkManager>,
 1169    show_cursor_names: bool,
 1170    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1171    pub show_local_selections: bool,
 1172    mode: EditorMode,
 1173    show_breadcrumbs: bool,
 1174    show_gutter: bool,
 1175    show_scrollbars: ScrollbarAxes,
 1176    minimap_visibility: MinimapVisibility,
 1177    offset_content: bool,
 1178    disable_expand_excerpt_buttons: bool,
 1179    delegate_expand_excerpts: bool,
 1180    delegate_stage_and_restore: bool,
 1181    delegate_open_excerpts: bool,
 1182    enable_lsp_data: bool,
 1183    enable_runnables: bool,
 1184    show_line_numbers: Option<bool>,
 1185    use_relative_line_numbers: Option<bool>,
 1186    show_git_diff_gutter: Option<bool>,
 1187    show_code_actions: Option<bool>,
 1188    show_runnables: Option<bool>,
 1189    show_breakpoints: Option<bool>,
 1190    show_diff_review_button: bool,
 1191    show_wrap_guides: Option<bool>,
 1192    show_indent_guides: Option<bool>,
 1193    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1194    highlight_order: usize,
 1195    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1196    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1197    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1198    scrollbar_marker_state: ScrollbarMarkerState,
 1199    active_indent_guides_state: ActiveIndentGuidesState,
 1200    nav_history: Option<ItemNavHistory>,
 1201    context_menu: RefCell<Option<CodeContextMenu>>,
 1202    context_menu_options: Option<ContextMenuOptions>,
 1203    mouse_context_menu: Option<MouseContextMenu>,
 1204    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1205    inline_blame_popover: Option<InlineBlamePopover>,
 1206    inline_blame_popover_show_task: Option<Task<()>>,
 1207    signature_help_state: SignatureHelpState,
 1208    auto_signature_help: Option<bool>,
 1209    find_all_references_task_sources: Vec<Anchor>,
 1210    next_completion_id: CompletionId,
 1211    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1212    code_actions_task: Option<Task<Result<()>>>,
 1213    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1214    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1215    debounced_selection_highlight_complete: bool,
 1216    document_highlights_task: Option<Task<()>>,
 1217    linked_editing_range_task: Option<Task<Option<()>>>,
 1218    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1219    pending_rename: Option<RenameState>,
 1220    searchable: bool,
 1221    cursor_shape: CursorShape,
 1222    /// Whether the cursor is offset one character to the left when something is
 1223    /// selected (needed for vim visual mode)
 1224    cursor_offset_on_selection: bool,
 1225    current_line_highlight: Option<CurrentLineHighlight>,
 1226    /// Whether to collapse search match ranges to just their start position.
 1227    /// When true, navigating to a match positions the cursor at the match
 1228    /// without selecting the matched text.
 1229    collapse_matches: bool,
 1230    autoindent_mode: Option<AutoindentMode>,
 1231    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1232    input_enabled: bool,
 1233    use_modal_editing: bool,
 1234    read_only: bool,
 1235    leader_id: Option<CollaboratorId>,
 1236    remote_id: Option<ViewId>,
 1237    pub hover_state: HoverState,
 1238    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1239    prev_pressure_stage: Option<PressureStage>,
 1240    gutter_hovered: bool,
 1241    hovered_link_state: Option<HoveredLinkState>,
 1242    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1243    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1244    active_edit_prediction: Option<EditPredictionState>,
 1245    /// Used to prevent flickering as the user types while the menu is open
 1246    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1247    edit_prediction_settings: EditPredictionSettings,
 1248    edit_predictions_hidden_for_vim_mode: bool,
 1249    show_edit_predictions_override: Option<bool>,
 1250    show_completions_on_input_override: Option<bool>,
 1251    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1252    edit_prediction_preview: EditPredictionPreview,
 1253    edit_prediction_indent_conflict: bool,
 1254    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1255    next_inlay_id: usize,
 1256    next_color_inlay_id: usize,
 1257    _subscriptions: Vec<Subscription>,
 1258    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1259    gutter_dimensions: GutterDimensions,
 1260    style: Option<EditorStyle>,
 1261    text_style_refinement: Option<TextStyleRefinement>,
 1262    next_editor_action_id: EditorActionId,
 1263    editor_actions: Rc<
 1264        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1265    >,
 1266    use_autoclose: bool,
 1267    use_auto_surround: bool,
 1268    auto_replace_emoji_shortcode: bool,
 1269    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1270    show_git_blame_gutter: bool,
 1271    show_git_blame_inline: bool,
 1272    show_git_blame_inline_delay_task: Option<Task<()>>,
 1273    git_blame_inline_enabled: bool,
 1274    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1275    buffer_serialization: Option<BufferSerialization>,
 1276    show_selection_menu: Option<bool>,
 1277    blame: Option<Entity<GitBlame>>,
 1278    blame_subscription: Option<Subscription>,
 1279    custom_context_menu: Option<
 1280        Box<
 1281            dyn 'static
 1282                + Fn(
 1283                    &mut Self,
 1284                    DisplayPoint,
 1285                    &mut Window,
 1286                    &mut Context<Self>,
 1287                ) -> Option<Entity<ui::ContextMenu>>,
 1288        >,
 1289    >,
 1290    last_bounds: Option<Bounds<Pixels>>,
 1291    last_position_map: Option<Rc<PositionMap>>,
 1292    expect_bounds_change: Option<Bounds<Pixels>>,
 1293    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1294    tasks_update_task: Option<Task<()>>,
 1295    breakpoint_store: Option<Entity<BreakpointStore>>,
 1296    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1297    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1298    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1299    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1300    /// when hunks have comments stored.
 1301    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1302    /// Stored review comments grouped by hunk.
 1303    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1304    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1305    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1306    /// Counter for generating unique comment IDs.
 1307    next_review_comment_id: usize,
 1308    hovered_diff_hunk_row: Option<DisplayRow>,
 1309    pull_diagnostics_task: Task<()>,
 1310    in_project_search: bool,
 1311    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1312    breadcrumb_header: Option<String>,
 1313    focused_block: Option<FocusedBlock>,
 1314    next_scroll_position: NextScrollCursorCenterTopBottom,
 1315    addons: HashMap<TypeId, Box<dyn Addon>>,
 1316    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1317    load_diff_task: Option<Shared<Task<()>>>,
 1318    /// Whether we are temporarily displaying a diff other than git's
 1319    temporary_diff_override: bool,
 1320    selection_mark_mode: bool,
 1321    toggle_fold_multiple_buffers: Task<()>,
 1322    _scroll_cursor_center_top_bottom_task: Task<()>,
 1323    serialize_selections: Task<()>,
 1324    serialize_folds: Task<()>,
 1325    mouse_cursor_hidden: bool,
 1326    minimap: Option<Entity<Self>>,
 1327    hide_mouse_mode: HideMouseMode,
 1328    pub change_list: ChangeList,
 1329    inline_value_cache: InlineValueCache,
 1330    number_deleted_lines: bool,
 1331
 1332    selection_drag_state: SelectionDragState,
 1333    colors: Option<LspColorData>,
 1334    post_scroll_update: Task<()>,
 1335    refresh_colors_task: Task<()>,
 1336    use_document_folding_ranges: bool,
 1337    refresh_folding_ranges_task: Task<()>,
 1338    inlay_hints: Option<LspInlayHintData>,
 1339    folding_newlines: Task<()>,
 1340    select_next_is_case_sensitive: Option<bool>,
 1341    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1342    on_local_selections_changed:
 1343        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1344    suppress_selection_callback: bool,
 1345    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1346    accent_data: Option<AccentData>,
 1347    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1348    semantic_token_state: SemanticTokenState,
 1349    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1350    refresh_outline_symbols_task: Task<()>,
 1351    outline_symbols: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1352    sticky_headers_task: Task<()>,
 1353    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1354}
 1355
 1356#[derive(Debug, PartialEq)]
 1357struct AccentData {
 1358    colors: AccentColors,
 1359    overrides: Vec<SharedString>,
 1360}
 1361
 1362fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1363    if debounce_ms > 0 {
 1364        Some(Duration::from_millis(debounce_ms))
 1365    } else {
 1366        None
 1367    }
 1368}
 1369
 1370#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1371enum NextScrollCursorCenterTopBottom {
 1372    #[default]
 1373    Center,
 1374    Top,
 1375    Bottom,
 1376}
 1377
 1378impl NextScrollCursorCenterTopBottom {
 1379    fn next(&self) -> Self {
 1380        match self {
 1381            Self::Center => Self::Top,
 1382            Self::Top => Self::Bottom,
 1383            Self::Bottom => Self::Center,
 1384        }
 1385    }
 1386}
 1387
 1388#[derive(Clone)]
 1389pub struct EditorSnapshot {
 1390    pub mode: EditorMode,
 1391    show_gutter: bool,
 1392    offset_content: bool,
 1393    show_line_numbers: Option<bool>,
 1394    number_deleted_lines: bool,
 1395    show_git_diff_gutter: Option<bool>,
 1396    show_code_actions: Option<bool>,
 1397    show_runnables: Option<bool>,
 1398    show_breakpoints: Option<bool>,
 1399    git_blame_gutter_max_author_length: Option<usize>,
 1400    pub display_snapshot: DisplaySnapshot,
 1401    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1402    is_focused: bool,
 1403    scroll_anchor: SharedScrollAnchor,
 1404    ongoing_scroll: OngoingScroll,
 1405    current_line_highlight: CurrentLineHighlight,
 1406    gutter_hovered: bool,
 1407    semantic_tokens_enabled: bool,
 1408}
 1409
 1410#[derive(Default, Debug, Clone, Copy)]
 1411pub struct GutterDimensions {
 1412    pub left_padding: Pixels,
 1413    pub right_padding: Pixels,
 1414    pub width: Pixels,
 1415    pub margin: Pixels,
 1416    pub git_blame_entries_width: Option<Pixels>,
 1417}
 1418
 1419impl GutterDimensions {
 1420    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1421        Self {
 1422            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1423            ..Default::default()
 1424        }
 1425    }
 1426
 1427    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1428        -cx.text_system().descent(font_id, font_size)
 1429    }
 1430    /// The full width of the space taken up by the gutter.
 1431    pub fn full_width(&self) -> Pixels {
 1432        self.margin + self.width
 1433    }
 1434
 1435    /// The width of the space reserved for the fold indicators,
 1436    /// use alongside 'justify_end' and `gutter_width` to
 1437    /// right align content with the line numbers
 1438    pub fn fold_area_width(&self) -> Pixels {
 1439        self.margin + self.right_padding
 1440    }
 1441}
 1442
 1443struct CharacterDimensions {
 1444    em_width: Pixels,
 1445    em_advance: Pixels,
 1446    line_height: Pixels,
 1447}
 1448
 1449#[derive(Debug)]
 1450pub struct RemoteSelection {
 1451    pub replica_id: ReplicaId,
 1452    pub selection: Selection<Anchor>,
 1453    pub cursor_shape: CursorShape,
 1454    pub collaborator_id: CollaboratorId,
 1455    pub line_mode: bool,
 1456    pub user_name: Option<SharedString>,
 1457    pub color: PlayerColor,
 1458}
 1459
 1460#[derive(Clone, Debug)]
 1461struct SelectionHistoryEntry {
 1462    selections: Arc<[Selection<Anchor>]>,
 1463    select_next_state: Option<SelectNextState>,
 1464    select_prev_state: Option<SelectNextState>,
 1465    add_selections_state: Option<AddSelectionsState>,
 1466}
 1467
 1468#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1469enum SelectionHistoryMode {
 1470    #[default]
 1471    Normal,
 1472    Undoing,
 1473    Redoing,
 1474    Skipping,
 1475}
 1476
 1477#[derive(Clone, PartialEq, Eq, Hash)]
 1478struct HoveredCursor {
 1479    replica_id: ReplicaId,
 1480    selection_id: usize,
 1481}
 1482
 1483#[derive(Debug)]
 1484/// SelectionEffects controls the side-effects of updating the selection.
 1485///
 1486/// The default behaviour does "what you mostly want":
 1487/// - it pushes to the nav history if the cursor moved by >10 lines
 1488/// - it re-triggers completion requests
 1489/// - it scrolls to fit
 1490///
 1491/// You might want to modify these behaviours. For example when doing a "jump"
 1492/// like go to definition, we always want to add to nav history; but when scrolling
 1493/// in vim mode we never do.
 1494///
 1495/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1496/// move.
 1497#[derive(Clone)]
 1498pub struct SelectionEffects {
 1499    nav_history: Option<bool>,
 1500    completions: bool,
 1501    scroll: Option<Autoscroll>,
 1502}
 1503
 1504impl Default for SelectionEffects {
 1505    fn default() -> Self {
 1506        Self {
 1507            nav_history: None,
 1508            completions: true,
 1509            scroll: Some(Autoscroll::fit()),
 1510        }
 1511    }
 1512}
 1513impl SelectionEffects {
 1514    pub fn scroll(scroll: Autoscroll) -> Self {
 1515        Self {
 1516            scroll: Some(scroll),
 1517            ..Default::default()
 1518        }
 1519    }
 1520
 1521    pub fn no_scroll() -> Self {
 1522        Self {
 1523            scroll: None,
 1524            ..Default::default()
 1525        }
 1526    }
 1527
 1528    pub fn completions(self, completions: bool) -> Self {
 1529        Self {
 1530            completions,
 1531            ..self
 1532        }
 1533    }
 1534
 1535    pub fn nav_history(self, nav_history: bool) -> Self {
 1536        Self {
 1537            nav_history: Some(nav_history),
 1538            ..self
 1539        }
 1540    }
 1541}
 1542
 1543struct DeferredSelectionEffectsState {
 1544    changed: bool,
 1545    effects: SelectionEffects,
 1546    old_cursor_position: Anchor,
 1547    history_entry: SelectionHistoryEntry,
 1548}
 1549
 1550#[derive(Default)]
 1551struct SelectionHistory {
 1552    #[allow(clippy::type_complexity)]
 1553    selections_by_transaction:
 1554        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1555    mode: SelectionHistoryMode,
 1556    undo_stack: VecDeque<SelectionHistoryEntry>,
 1557    redo_stack: VecDeque<SelectionHistoryEntry>,
 1558}
 1559
 1560impl SelectionHistory {
 1561    #[track_caller]
 1562    fn insert_transaction(
 1563        &mut self,
 1564        transaction_id: TransactionId,
 1565        selections: Arc<[Selection<Anchor>]>,
 1566    ) {
 1567        if selections.is_empty() {
 1568            log::error!(
 1569                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1570                std::panic::Location::caller()
 1571            );
 1572            return;
 1573        }
 1574        self.selections_by_transaction
 1575            .insert(transaction_id, (selections, None));
 1576    }
 1577
 1578    #[allow(clippy::type_complexity)]
 1579    fn transaction(
 1580        &self,
 1581        transaction_id: TransactionId,
 1582    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1583        self.selections_by_transaction.get(&transaction_id)
 1584    }
 1585
 1586    #[allow(clippy::type_complexity)]
 1587    fn transaction_mut(
 1588        &mut self,
 1589        transaction_id: TransactionId,
 1590    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1591        self.selections_by_transaction.get_mut(&transaction_id)
 1592    }
 1593
 1594    fn push(&mut self, entry: SelectionHistoryEntry) {
 1595        if !entry.selections.is_empty() {
 1596            match self.mode {
 1597                SelectionHistoryMode::Normal => {
 1598                    self.push_undo(entry);
 1599                    self.redo_stack.clear();
 1600                }
 1601                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1602                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1603                SelectionHistoryMode::Skipping => {}
 1604            }
 1605        }
 1606    }
 1607
 1608    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1609        if self
 1610            .undo_stack
 1611            .back()
 1612            .is_none_or(|e| e.selections != entry.selections)
 1613        {
 1614            self.undo_stack.push_back(entry);
 1615            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1616                self.undo_stack.pop_front();
 1617            }
 1618        }
 1619    }
 1620
 1621    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1622        if self
 1623            .redo_stack
 1624            .back()
 1625            .is_none_or(|e| e.selections != entry.selections)
 1626        {
 1627            self.redo_stack.push_back(entry);
 1628            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1629                self.redo_stack.pop_front();
 1630            }
 1631        }
 1632    }
 1633}
 1634
 1635#[derive(Clone, Copy)]
 1636pub struct RowHighlightOptions {
 1637    pub autoscroll: bool,
 1638    pub include_gutter: bool,
 1639}
 1640
 1641impl Default for RowHighlightOptions {
 1642    fn default() -> Self {
 1643        Self {
 1644            autoscroll: Default::default(),
 1645            include_gutter: true,
 1646        }
 1647    }
 1648}
 1649
 1650struct RowHighlight {
 1651    index: usize,
 1652    range: Range<Anchor>,
 1653    color: Hsla,
 1654    options: RowHighlightOptions,
 1655    type_id: TypeId,
 1656}
 1657
 1658#[derive(Clone, Debug)]
 1659struct AddSelectionsState {
 1660    groups: Vec<AddSelectionsGroup>,
 1661}
 1662
 1663#[derive(Clone, Debug)]
 1664struct AddSelectionsGroup {
 1665    above: bool,
 1666    stack: Vec<usize>,
 1667}
 1668
 1669#[derive(Clone)]
 1670struct SelectNextState {
 1671    query: AhoCorasick,
 1672    wordwise: bool,
 1673    done: bool,
 1674}
 1675
 1676impl std::fmt::Debug for SelectNextState {
 1677    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1678        f.debug_struct(std::any::type_name::<Self>())
 1679            .field("wordwise", &self.wordwise)
 1680            .field("done", &self.done)
 1681            .finish()
 1682    }
 1683}
 1684
 1685#[derive(Debug)]
 1686struct AutocloseRegion {
 1687    selection_id: usize,
 1688    range: Range<Anchor>,
 1689    pair: BracketPair,
 1690}
 1691
 1692#[derive(Debug)]
 1693struct SnippetState {
 1694    ranges: Vec<Vec<Range<Anchor>>>,
 1695    active_index: usize,
 1696    choices: Vec<Option<Vec<String>>>,
 1697}
 1698
 1699#[doc(hidden)]
 1700pub struct RenameState {
 1701    pub range: Range<Anchor>,
 1702    pub old_name: Arc<str>,
 1703    pub editor: Entity<Editor>,
 1704    block_id: CustomBlockId,
 1705}
 1706
 1707struct InvalidationStack<T>(Vec<T>);
 1708
 1709struct RegisteredEditPredictionDelegate {
 1710    provider: Arc<dyn EditPredictionDelegateHandle>,
 1711    _subscription: Subscription,
 1712}
 1713
 1714#[derive(Debug, PartialEq, Eq)]
 1715pub struct ActiveDiagnosticGroup {
 1716    pub active_range: Range<Anchor>,
 1717    pub active_message: String,
 1718    pub group_id: usize,
 1719    pub blocks: HashSet<CustomBlockId>,
 1720}
 1721
 1722#[derive(Debug, PartialEq, Eq)]
 1723
 1724pub(crate) enum ActiveDiagnostic {
 1725    None,
 1726    All,
 1727    Group(ActiveDiagnosticGroup),
 1728}
 1729
 1730#[derive(Serialize, Deserialize, Clone, Debug)]
 1731pub struct ClipboardSelection {
 1732    /// The number of bytes in this selection.
 1733    pub len: usize,
 1734    /// Whether this was a full-line selection.
 1735    pub is_entire_line: bool,
 1736    /// The indentation of the first line when this content was originally copied.
 1737    pub first_line_indent: u32,
 1738    #[serde(default)]
 1739    pub file_path: Option<PathBuf>,
 1740    #[serde(default)]
 1741    pub line_range: Option<RangeInclusive<u32>>,
 1742}
 1743
 1744impl ClipboardSelection {
 1745    pub fn for_buffer(
 1746        len: usize,
 1747        is_entire_line: bool,
 1748        range: Range<Point>,
 1749        buffer: &MultiBufferSnapshot,
 1750        project: Option<&Entity<Project>>,
 1751        cx: &App,
 1752    ) -> Self {
 1753        let first_line_indent = buffer
 1754            .indent_size_for_line(MultiBufferRow(range.start.row))
 1755            .len;
 1756
 1757        let file_path = util::maybe!({
 1758            let project = project?.read(cx);
 1759            let file = buffer.file_at(range.start)?;
 1760            let project_path = ProjectPath {
 1761                worktree_id: file.worktree_id(cx),
 1762                path: file.path().clone(),
 1763            };
 1764            project.absolute_path(&project_path, cx)
 1765        });
 1766
 1767        let line_range = file_path.as_ref().and_then(|_| {
 1768            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1769            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1770            if start_excerpt_id == end_excerpt_id {
 1771                Some(start_point.row..=end_point.row)
 1772            } else {
 1773                None
 1774            }
 1775        });
 1776
 1777        Self {
 1778            len,
 1779            is_entire_line,
 1780            first_line_indent,
 1781            file_path,
 1782            line_range,
 1783        }
 1784    }
 1785}
 1786
 1787// selections, scroll behavior, was newest selection reversed
 1788type SelectSyntaxNodeHistoryState = (
 1789    Box<[Selection<MultiBufferOffset>]>,
 1790    SelectSyntaxNodeScrollBehavior,
 1791    bool,
 1792);
 1793
 1794#[derive(Default)]
 1795struct SelectSyntaxNodeHistory {
 1796    stack: Vec<SelectSyntaxNodeHistoryState>,
 1797    // disable temporarily to allow changing selections without losing the stack
 1798    pub disable_clearing: bool,
 1799}
 1800
 1801impl SelectSyntaxNodeHistory {
 1802    pub fn try_clear(&mut self) {
 1803        if !self.disable_clearing {
 1804            self.stack.clear();
 1805        }
 1806    }
 1807
 1808    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1809        self.stack.push(selection);
 1810    }
 1811
 1812    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1813        self.stack.pop()
 1814    }
 1815}
 1816
 1817enum SelectSyntaxNodeScrollBehavior {
 1818    CursorTop,
 1819    FitSelection,
 1820    CursorBottom,
 1821}
 1822
 1823#[derive(Debug, Clone, Copy)]
 1824pub(crate) struct NavigationData {
 1825    cursor_anchor: Anchor,
 1826    cursor_position: Point,
 1827    scroll_anchor: ScrollAnchor,
 1828    scroll_top_row: u32,
 1829}
 1830
 1831#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1832pub enum GotoDefinitionKind {
 1833    Symbol,
 1834    Declaration,
 1835    Type,
 1836    Implementation,
 1837}
 1838
 1839pub enum FormatTarget {
 1840    Buffers(HashSet<Entity<Buffer>>),
 1841    Ranges(Vec<Range<MultiBufferPoint>>),
 1842}
 1843
 1844pub(crate) struct FocusedBlock {
 1845    id: BlockId,
 1846    focus_handle: WeakFocusHandle,
 1847}
 1848
 1849#[derive(Clone, Debug)]
 1850pub enum JumpData {
 1851    MultiBufferRow {
 1852        row: MultiBufferRow,
 1853        line_offset_from_top: u32,
 1854    },
 1855    MultiBufferPoint {
 1856        excerpt_id: ExcerptId,
 1857        position: Point,
 1858        anchor: text::Anchor,
 1859        line_offset_from_top: u32,
 1860    },
 1861}
 1862
 1863pub enum MultibufferSelectionMode {
 1864    First,
 1865    All,
 1866}
 1867
 1868#[derive(Clone, Copy, Debug, Default)]
 1869pub struct RewrapOptions {
 1870    pub override_language_settings: bool,
 1871    pub preserve_existing_whitespace: bool,
 1872}
 1873
 1874impl Editor {
 1875    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1876        let buffer = cx.new(|cx| Buffer::local("", cx));
 1877        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1878        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1879    }
 1880
 1881    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1882        let buffer = cx.new(|cx| Buffer::local("", cx));
 1883        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1884        Self::new(EditorMode::full(), buffer, None, window, cx)
 1885    }
 1886
 1887    pub fn auto_height(
 1888        min_lines: usize,
 1889        max_lines: usize,
 1890        window: &mut Window,
 1891        cx: &mut Context<Self>,
 1892    ) -> Self {
 1893        let buffer = cx.new(|cx| Buffer::local("", cx));
 1894        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1895        Self::new(
 1896            EditorMode::AutoHeight {
 1897                min_lines,
 1898                max_lines: Some(max_lines),
 1899            },
 1900            buffer,
 1901            None,
 1902            window,
 1903            cx,
 1904        )
 1905    }
 1906
 1907    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1908    /// The editor grows as tall as needed to fit its content.
 1909    pub fn auto_height_unbounded(
 1910        min_lines: usize,
 1911        window: &mut Window,
 1912        cx: &mut Context<Self>,
 1913    ) -> Self {
 1914        let buffer = cx.new(|cx| Buffer::local("", cx));
 1915        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1916        Self::new(
 1917            EditorMode::AutoHeight {
 1918                min_lines,
 1919                max_lines: None,
 1920            },
 1921            buffer,
 1922            None,
 1923            window,
 1924            cx,
 1925        )
 1926    }
 1927
 1928    pub fn for_buffer(
 1929        buffer: Entity<Buffer>,
 1930        project: Option<Entity<Project>>,
 1931        window: &mut Window,
 1932        cx: &mut Context<Self>,
 1933    ) -> Self {
 1934        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1935        Self::new(EditorMode::full(), buffer, project, window, cx)
 1936    }
 1937
 1938    pub fn for_multibuffer(
 1939        buffer: Entity<MultiBuffer>,
 1940        project: Option<Entity<Project>>,
 1941        window: &mut Window,
 1942        cx: &mut Context<Self>,
 1943    ) -> Self {
 1944        Self::new(EditorMode::full(), buffer, project, window, cx)
 1945    }
 1946
 1947    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1948        let mut clone = Self::new(
 1949            self.mode.clone(),
 1950            self.buffer.clone(),
 1951            self.project.clone(),
 1952            window,
 1953            cx,
 1954        );
 1955        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1956            let snapshot = display_map.snapshot(cx);
 1957            clone.display_map.update(cx, |display_map, cx| {
 1958                display_map.set_state(&snapshot, cx);
 1959            });
 1960            snapshot
 1961        });
 1962        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1963        clone.folds_did_change(cx);
 1964        clone.selections.clone_state(&self.selections);
 1965        clone
 1966            .scroll_manager
 1967            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1968        clone.searchable = self.searchable;
 1969        clone.read_only = self.read_only;
 1970        clone
 1971    }
 1972
 1973    pub fn new(
 1974        mode: EditorMode,
 1975        buffer: Entity<MultiBuffer>,
 1976        project: Option<Entity<Project>>,
 1977        window: &mut Window,
 1978        cx: &mut Context<Self>,
 1979    ) -> Self {
 1980        Editor::new_internal(mode, buffer, project, None, window, cx)
 1981    }
 1982
 1983    pub fn refresh_sticky_headers(
 1984        &mut self,
 1985        display_snapshot: &DisplaySnapshot,
 1986        cx: &mut Context<Editor>,
 1987    ) {
 1988        if !self.mode.is_full() {
 1989            return;
 1990        }
 1991        let multi_buffer = display_snapshot.buffer_snapshot();
 1992        let multi_buffer_visible_start = self
 1993            .scroll_manager
 1994            .native_anchor(display_snapshot, cx)
 1995            .anchor
 1996            .to_point(&multi_buffer);
 1997        let max_row = multi_buffer.max_point().row;
 1998
 1999        let start_row = (multi_buffer_visible_start.row).min(max_row);
 2000        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 2001        let Some((excerpt_id, _, buffer)) = multi_buffer.as_singleton() else {
 2002            return;
 2003        };
 2004        let buffer = buffer.clone();
 2005        let &excerpt_id = excerpt_id;
 2006        let syntax = self.style(cx).syntax.clone();
 2007        let background_task = cx.background_spawn(async move {
 2008            buffer
 2009                .outline_items_containing(
 2010                    Point::new(start_row, 0)..Point::new(end_row, 0),
 2011                    true,
 2012                    Some(syntax.as_ref()),
 2013                )
 2014                .into_iter()
 2015                .map(|outline_item| OutlineItem {
 2016                    depth: outline_item.depth,
 2017                    range: Anchor::range_in_buffer(excerpt_id, outline_item.range),
 2018                    source_range_for_text: Anchor::range_in_buffer(
 2019                        excerpt_id,
 2020                        outline_item.source_range_for_text,
 2021                    ),
 2022                    text: outline_item.text,
 2023                    highlight_ranges: outline_item.highlight_ranges,
 2024                    name_ranges: outline_item.name_ranges,
 2025                    body_range: outline_item
 2026                        .body_range
 2027                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2028                    annotation_range: outline_item
 2029                        .annotation_range
 2030                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2031                })
 2032                .collect()
 2033        });
 2034        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2035            let sticky_headers = background_task.await;
 2036            this.update(cx, |this, cx| {
 2037                this.sticky_headers = Some(sticky_headers);
 2038                cx.notify();
 2039            })
 2040            .ok();
 2041        });
 2042    }
 2043
 2044    fn new_internal(
 2045        mode: EditorMode,
 2046        multi_buffer: Entity<MultiBuffer>,
 2047        project: Option<Entity<Project>>,
 2048        display_map: Option<Entity<DisplayMap>>,
 2049        window: &mut Window,
 2050        cx: &mut Context<Self>,
 2051    ) -> Self {
 2052        debug_assert!(
 2053            display_map.is_none() || mode.is_minimap(),
 2054            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2055        );
 2056
 2057        let full_mode = mode.is_full();
 2058        let is_minimap = mode.is_minimap();
 2059        let diagnostics_max_severity = if full_mode {
 2060            EditorSettings::get_global(cx)
 2061                .diagnostics_max_severity
 2062                .unwrap_or(DiagnosticSeverity::Hint)
 2063        } else {
 2064            DiagnosticSeverity::Off
 2065        };
 2066        let style = window.text_style();
 2067        let font_size = style.font_size.to_pixels(window.rem_size());
 2068        let editor = cx.entity().downgrade();
 2069        let fold_placeholder = FoldPlaceholder {
 2070            constrain_width: false,
 2071            render: Arc::new(move |fold_id, fold_range, cx| {
 2072                let editor = editor.clone();
 2073                FoldPlaceholder::fold_element(fold_id, cx)
 2074                    .cursor_pointer()
 2075                    .child("")
 2076                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2077                    .on_click(move |_, _window, cx| {
 2078                        editor
 2079                            .update(cx, |editor, cx| {
 2080                                editor.unfold_ranges(
 2081                                    &[fold_range.start..fold_range.end],
 2082                                    true,
 2083                                    false,
 2084                                    cx,
 2085                                );
 2086                                cx.stop_propagation();
 2087                            })
 2088                            .ok();
 2089                    })
 2090                    .into_any()
 2091            }),
 2092            merge_adjacent: true,
 2093            ..FoldPlaceholder::default()
 2094        };
 2095        let display_map = display_map.unwrap_or_else(|| {
 2096            cx.new(|cx| {
 2097                DisplayMap::new(
 2098                    multi_buffer.clone(),
 2099                    style.font(),
 2100                    font_size,
 2101                    None,
 2102                    FILE_HEADER_HEIGHT,
 2103                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2104                    fold_placeholder,
 2105                    diagnostics_max_severity,
 2106                    cx,
 2107                )
 2108            })
 2109        });
 2110
 2111        let selections = SelectionsCollection::new();
 2112
 2113        let blink_manager = cx.new(|cx| {
 2114            let mut blink_manager = BlinkManager::new(
 2115                CURSOR_BLINK_INTERVAL,
 2116                |cx| EditorSettings::get_global(cx).cursor_blink,
 2117                cx,
 2118            );
 2119            if is_minimap {
 2120                blink_manager.disable(cx);
 2121            }
 2122            blink_manager
 2123        });
 2124
 2125        let soft_wrap_mode_override =
 2126            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2127
 2128        let mut project_subscriptions = Vec::new();
 2129        if full_mode && let Some(project) = project.as_ref() {
 2130            project_subscriptions.push(cx.subscribe_in(
 2131                project,
 2132                window,
 2133                |editor, _, event, window, cx| match event {
 2134                    project::Event::RefreshCodeLens => {
 2135                        // we always query lens with actions, without storing them, always refreshing them
 2136                    }
 2137                    project::Event::RefreshInlayHints {
 2138                        server_id,
 2139                        request_id,
 2140                    } => {
 2141                        editor.refresh_inlay_hints(
 2142                            InlayHintRefreshReason::RefreshRequested {
 2143                                server_id: *server_id,
 2144                                request_id: *request_id,
 2145                            },
 2146                            cx,
 2147                        );
 2148                    }
 2149                    project::Event::RefreshSemanticTokens {
 2150                        server_id,
 2151                        request_id,
 2152                    } => {
 2153                        editor.update_semantic_tokens(
 2154                            None,
 2155                            Some(RefreshForServer {
 2156                                server_id: *server_id,
 2157                                request_id: *request_id,
 2158                            }),
 2159                            cx,
 2160                        );
 2161                    }
 2162                    project::Event::LanguageServerRemoved(_server_id) => {
 2163                        editor.registered_buffers.clear();
 2164                        editor.register_visible_buffers(cx);
 2165                        editor.update_lsp_data(None, window, cx);
 2166                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2167                        if editor.tasks_update_task.is_none() {
 2168                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2169                        }
 2170                    }
 2171                    project::Event::LanguageServerAdded(..) => {
 2172                        if editor.tasks_update_task.is_none() {
 2173                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2174                        }
 2175                    }
 2176                    project::Event::SnippetEdit(id, snippet_edits) => {
 2177                        // todo(lw): Non singletons
 2178                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2179                            let snapshot = buffer.read(cx).snapshot();
 2180                            let focus_handle = editor.focus_handle(cx);
 2181                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2182                                for (range, snippet) in snippet_edits {
 2183                                    let buffer_range =
 2184                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2185                                    editor
 2186                                        .insert_snippet(
 2187                                            &[MultiBufferOffset(buffer_range.start)
 2188                                                ..MultiBufferOffset(buffer_range.end)],
 2189                                            snippet.clone(),
 2190                                            window,
 2191                                            cx,
 2192                                        )
 2193                                        .ok();
 2194                                }
 2195                            }
 2196                        }
 2197                    }
 2198                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2199                        let buffer_id = *buffer_id;
 2200                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2201                            editor.register_buffer(buffer_id, cx);
 2202                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2203                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2204                            refresh_linked_ranges(editor, window, cx);
 2205                            editor.refresh_code_actions(window, cx);
 2206                            editor.refresh_document_highlights(cx);
 2207                        }
 2208                    }
 2209
 2210                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2211                        let Some(workspace) = editor.workspace() else {
 2212                            return;
 2213                        };
 2214                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2215                        else {
 2216                            return;
 2217                        };
 2218
 2219                        if active_editor.entity_id() == cx.entity_id() {
 2220                            let entity_id = cx.entity_id();
 2221                            workspace.update(cx, |this, cx| {
 2222                                this.panes_mut()
 2223                                    .iter_mut()
 2224                                    .filter(|pane| pane.entity_id() != entity_id)
 2225                                    .for_each(|p| {
 2226                                        p.update(cx, |pane, _| {
 2227                                            pane.nav_history_mut().rename_item(
 2228                                                entity_id,
 2229                                                project_path.clone(),
 2230                                                abs_path.clone().into(),
 2231                                            );
 2232                                        })
 2233                                    });
 2234                            });
 2235
 2236                            Self::open_transaction_for_hidden_buffers(
 2237                                workspace,
 2238                                transaction.clone(),
 2239                                "Rename".to_string(),
 2240                                window,
 2241                                cx,
 2242                            );
 2243                        }
 2244                    }
 2245
 2246                    project::Event::WorkspaceEditApplied(transaction) => {
 2247                        let Some(workspace) = editor.workspace() else {
 2248                            return;
 2249                        };
 2250                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2251                        else {
 2252                            return;
 2253                        };
 2254
 2255                        if active_editor.entity_id() == cx.entity_id() {
 2256                            Self::open_transaction_for_hidden_buffers(
 2257                                workspace,
 2258                                transaction.clone(),
 2259                                "LSP Edit".to_string(),
 2260                                window,
 2261                                cx,
 2262                            );
 2263                        }
 2264                    }
 2265
 2266                    _ => {}
 2267                },
 2268            ));
 2269            if let Some(task_inventory) = project
 2270                .read(cx)
 2271                .task_store()
 2272                .read(cx)
 2273                .task_inventory()
 2274                .cloned()
 2275            {
 2276                project_subscriptions.push(cx.observe_in(
 2277                    &task_inventory,
 2278                    window,
 2279                    |editor, _, window, cx| {
 2280                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2281                    },
 2282                ));
 2283            };
 2284
 2285            project_subscriptions.push(cx.subscribe_in(
 2286                &project.read(cx).breakpoint_store(),
 2287                window,
 2288                |editor, _, event, window, cx| match event {
 2289                    BreakpointStoreEvent::ClearDebugLines => {
 2290                        editor.clear_row_highlights::<ActiveDebugLine>();
 2291                        editor.refresh_inline_values(cx);
 2292                    }
 2293                    BreakpointStoreEvent::SetDebugLine => {
 2294                        if editor.go_to_active_debug_line(window, cx) {
 2295                            cx.stop_propagation();
 2296                        }
 2297
 2298                        editor.refresh_inline_values(cx);
 2299                    }
 2300                    _ => {}
 2301                },
 2302            ));
 2303            let git_store = project.read(cx).git_store().clone();
 2304            let project = project.clone();
 2305            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2306                if let GitStoreEvent::RepositoryAdded = event {
 2307                    this.load_diff_task = Some(
 2308                        update_uncommitted_diff_for_buffer(
 2309                            cx.entity(),
 2310                            &project,
 2311                            this.buffer.read(cx).all_buffers(),
 2312                            this.buffer.clone(),
 2313                            cx,
 2314                        )
 2315                        .shared(),
 2316                    );
 2317                }
 2318            }));
 2319        }
 2320
 2321        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2322
 2323        let inlay_hint_settings =
 2324            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2325        let focus_handle = cx.focus_handle();
 2326        if !is_minimap {
 2327            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2328                .detach();
 2329            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2330                .detach();
 2331            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2332                .detach();
 2333            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2334                .detach();
 2335            cx.observe_pending_input(window, Self::observe_pending_input)
 2336                .detach();
 2337        }
 2338
 2339        let show_indent_guides =
 2340            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2341                Some(false)
 2342            } else {
 2343                None
 2344            };
 2345
 2346        let breakpoint_store = match (&mode, project.as_ref()) {
 2347            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2348            _ => None,
 2349        };
 2350
 2351        let mut code_action_providers = Vec::new();
 2352        let mut load_uncommitted_diff = None;
 2353        if let Some(project) = project.clone() {
 2354            load_uncommitted_diff = Some(
 2355                update_uncommitted_diff_for_buffer(
 2356                    cx.entity(),
 2357                    &project,
 2358                    multi_buffer.read(cx).all_buffers(),
 2359                    multi_buffer.clone(),
 2360                    cx,
 2361                )
 2362                .shared(),
 2363            );
 2364            code_action_providers.push(Rc::new(project) as Rc<_>);
 2365        }
 2366
 2367        let mut editor = Self {
 2368            focus_handle,
 2369            show_cursor_when_unfocused: false,
 2370            last_focused_descendant: None,
 2371            buffer: multi_buffer.clone(),
 2372            display_map: display_map.clone(),
 2373            placeholder_display_map: None,
 2374            selections,
 2375            scroll_manager: ScrollManager::new(cx),
 2376            columnar_selection_state: None,
 2377            add_selections_state: None,
 2378            select_next_state: None,
 2379            select_prev_state: None,
 2380            selection_history: SelectionHistory::default(),
 2381            defer_selection_effects: false,
 2382            deferred_selection_effects_state: None,
 2383            autoclose_regions: Vec::new(),
 2384            snippet_stack: InvalidationStack::default(),
 2385            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2386            ime_transaction: None,
 2387            active_diagnostics: ActiveDiagnostic::None,
 2388            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2389            inline_diagnostics_update: Task::ready(()),
 2390            inline_diagnostics: Vec::new(),
 2391            soft_wrap_mode_override,
 2392            diagnostics_max_severity,
 2393            hard_wrap: None,
 2394            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2395            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2396            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2397            project,
 2398            blink_manager: blink_manager.clone(),
 2399            show_local_selections: true,
 2400            show_scrollbars: ScrollbarAxes {
 2401                horizontal: full_mode,
 2402                vertical: full_mode,
 2403            },
 2404            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2405            offset_content: !matches!(mode, EditorMode::SingleLine),
 2406            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2407            show_gutter: full_mode,
 2408            show_line_numbers: (!full_mode).then_some(false),
 2409            use_relative_line_numbers: None,
 2410            disable_expand_excerpt_buttons: !full_mode,
 2411            delegate_expand_excerpts: false,
 2412            delegate_stage_and_restore: false,
 2413            delegate_open_excerpts: false,
 2414            enable_lsp_data: true,
 2415            enable_runnables: true,
 2416            show_git_diff_gutter: None,
 2417            show_code_actions: None,
 2418            show_runnables: None,
 2419            show_breakpoints: None,
 2420            show_diff_review_button: false,
 2421            show_wrap_guides: None,
 2422            show_indent_guides,
 2423            buffers_with_disabled_indent_guides: HashSet::default(),
 2424            highlight_order: 0,
 2425            highlighted_rows: HashMap::default(),
 2426            background_highlights: HashMap::default(),
 2427            gutter_highlights: HashMap::default(),
 2428            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2429            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2430            nav_history: None,
 2431            context_menu: RefCell::new(None),
 2432            context_menu_options: None,
 2433            mouse_context_menu: None,
 2434            completion_tasks: Vec::new(),
 2435            inline_blame_popover: None,
 2436            inline_blame_popover_show_task: None,
 2437            signature_help_state: SignatureHelpState::default(),
 2438            auto_signature_help: None,
 2439            find_all_references_task_sources: Vec::new(),
 2440            next_completion_id: 0,
 2441            next_inlay_id: 0,
 2442            code_action_providers,
 2443            available_code_actions: None,
 2444            code_actions_task: None,
 2445            quick_selection_highlight_task: None,
 2446            debounced_selection_highlight_task: None,
 2447            debounced_selection_highlight_complete: false,
 2448            document_highlights_task: None,
 2449            linked_editing_range_task: None,
 2450            pending_rename: None,
 2451            searchable: !is_minimap,
 2452            cursor_shape: EditorSettings::get_global(cx)
 2453                .cursor_shape
 2454                .unwrap_or_default(),
 2455            cursor_offset_on_selection: false,
 2456            current_line_highlight: None,
 2457            autoindent_mode: Some(AutoindentMode::EachLine),
 2458            collapse_matches: false,
 2459            workspace: None,
 2460            input_enabled: !is_minimap,
 2461            use_modal_editing: full_mode,
 2462            read_only: is_minimap,
 2463            use_autoclose: true,
 2464            use_auto_surround: true,
 2465            auto_replace_emoji_shortcode: false,
 2466            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2467            leader_id: None,
 2468            remote_id: None,
 2469            hover_state: HoverState::default(),
 2470            pending_mouse_down: None,
 2471            prev_pressure_stage: None,
 2472            hovered_link_state: None,
 2473            edit_prediction_provider: None,
 2474            active_edit_prediction: None,
 2475            stale_edit_prediction_in_menu: None,
 2476            edit_prediction_preview: EditPredictionPreview::Inactive {
 2477                released_too_fast: false,
 2478            },
 2479            inline_diagnostics_enabled: full_mode,
 2480            diagnostics_enabled: full_mode,
 2481            word_completions_enabled: full_mode,
 2482            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2483            gutter_hovered: false,
 2484            pixel_position_of_newest_cursor: None,
 2485            last_bounds: None,
 2486            last_position_map: None,
 2487            expect_bounds_change: None,
 2488            gutter_dimensions: GutterDimensions::default(),
 2489            style: None,
 2490            show_cursor_names: false,
 2491            hovered_cursors: HashMap::default(),
 2492            next_editor_action_id: EditorActionId::default(),
 2493            editor_actions: Rc::default(),
 2494            edit_predictions_hidden_for_vim_mode: false,
 2495            show_edit_predictions_override: None,
 2496            show_completions_on_input_override: None,
 2497            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2498            edit_prediction_settings: EditPredictionSettings::Disabled,
 2499            edit_prediction_indent_conflict: false,
 2500            edit_prediction_requires_modifier_in_indent_conflict: true,
 2501            custom_context_menu: None,
 2502            show_git_blame_gutter: false,
 2503            show_git_blame_inline: false,
 2504            show_selection_menu: None,
 2505            show_git_blame_inline_delay_task: None,
 2506            git_blame_inline_enabled: full_mode
 2507                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2508            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2509            buffer_serialization: is_minimap.not().then(|| {
 2510                BufferSerialization::new(
 2511                    ProjectSettings::get_global(cx)
 2512                        .session
 2513                        .restore_unsaved_buffers,
 2514                )
 2515            }),
 2516            blame: None,
 2517            blame_subscription: None,
 2518            tasks: BTreeMap::default(),
 2519
 2520            breakpoint_store,
 2521            gutter_breakpoint_indicator: (None, None),
 2522            gutter_diff_review_indicator: (None, None),
 2523            diff_review_drag_state: None,
 2524            diff_review_overlays: Vec::new(),
 2525            stored_review_comments: Vec::new(),
 2526            next_review_comment_id: 0,
 2527            hovered_diff_hunk_row: None,
 2528            _subscriptions: (!is_minimap)
 2529                .then(|| {
 2530                    vec![
 2531                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2532                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2533                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2534                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2535                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2536                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2537                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2538                        cx.observe_window_activation(window, |editor, window, cx| {
 2539                            let active = window.is_window_active();
 2540                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2541                                if active {
 2542                                    blink_manager.enable(cx);
 2543                                } else {
 2544                                    blink_manager.disable(cx);
 2545                                }
 2546                            });
 2547                            if active {
 2548                                editor.show_mouse_cursor(cx);
 2549                            }
 2550                        }),
 2551                    ]
 2552                })
 2553                .unwrap_or_default(),
 2554            tasks_update_task: None,
 2555            pull_diagnostics_task: Task::ready(()),
 2556            colors: None,
 2557            refresh_colors_task: Task::ready(()),
 2558            use_document_folding_ranges: false,
 2559            refresh_folding_ranges_task: Task::ready(()),
 2560            inlay_hints: None,
 2561            next_color_inlay_id: 0,
 2562            post_scroll_update: Task::ready(()),
 2563            linked_edit_ranges: Default::default(),
 2564            in_project_search: false,
 2565            previous_search_ranges: None,
 2566            breadcrumb_header: None,
 2567            focused_block: None,
 2568            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2569            addons: HashMap::default(),
 2570            registered_buffers: HashMap::default(),
 2571            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2572            selection_mark_mode: false,
 2573            toggle_fold_multiple_buffers: Task::ready(()),
 2574            serialize_selections: Task::ready(()),
 2575            serialize_folds: Task::ready(()),
 2576            text_style_refinement: None,
 2577            load_diff_task: load_uncommitted_diff,
 2578            temporary_diff_override: false,
 2579            mouse_cursor_hidden: false,
 2580            minimap: None,
 2581            hide_mouse_mode: EditorSettings::get_global(cx)
 2582                .hide_mouse
 2583                .unwrap_or_default(),
 2584            change_list: ChangeList::new(),
 2585            mode,
 2586            selection_drag_state: SelectionDragState::None,
 2587            folding_newlines: Task::ready(()),
 2588            lookup_key: None,
 2589            select_next_is_case_sensitive: None,
 2590            on_local_selections_changed: None,
 2591            suppress_selection_callback: false,
 2592            applicable_language_settings: HashMap::default(),
 2593            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2594            accent_data: None,
 2595            fetched_tree_sitter_chunks: HashMap::default(),
 2596            number_deleted_lines: false,
 2597            refresh_matching_bracket_highlights_task: Task::ready(()),
 2598            refresh_outline_symbols_task: Task::ready(()),
 2599            outline_symbols: None,
 2600            sticky_headers_task: Task::ready(()),
 2601            sticky_headers: None,
 2602        };
 2603
 2604        if is_minimap {
 2605            return editor;
 2606        }
 2607
 2608        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2609        editor.accent_data = editor.fetch_accent_data(cx);
 2610
 2611        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2612            editor
 2613                ._subscriptions
 2614                .push(cx.observe(breakpoints, |_, _, cx| {
 2615                    cx.notify();
 2616                }));
 2617        }
 2618        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2619        editor._subscriptions.extend(project_subscriptions);
 2620
 2621        editor._subscriptions.push(cx.subscribe_in(
 2622            &cx.entity(),
 2623            window,
 2624            |editor, _, e: &EditorEvent, window, cx| match e {
 2625                EditorEvent::ScrollPositionChanged { local, .. } => {
 2626                    if *local {
 2627                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2628                        editor.inline_blame_popover.take();
 2629                        let snapshot = editor.snapshot(window, cx);
 2630                        let new_anchor = editor
 2631                            .scroll_manager
 2632                            .native_anchor(&snapshot.display_snapshot, cx);
 2633                        editor.update_restoration_data(cx, move |data| {
 2634                            data.scroll_position = (
 2635                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2636                                new_anchor.offset,
 2637                            );
 2638                        });
 2639
 2640                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2641                            cx.background_executor()
 2642                                .timer(Duration::from_millis(50))
 2643                                .await;
 2644                            editor
 2645                                .update_in(cx, |editor, window, cx| {
 2646                                    editor.register_visible_buffers(cx);
 2647                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2648                                    editor.refresh_folding_ranges(None, window, cx);
 2649                                    editor.refresh_inlay_hints(
 2650                                        InlayHintRefreshReason::NewLinesShown,
 2651                                        cx,
 2652                                    );
 2653                                    editor.colorize_brackets(false, cx);
 2654                                })
 2655                                .ok();
 2656                        });
 2657                    }
 2658                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2659                }
 2660                EditorEvent::Edited { .. } => {
 2661                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2662                        .map(|vim_mode| vim_mode.0)
 2663                        .unwrap_or(false);
 2664                    if !vim_mode {
 2665                        let display_map = editor.display_snapshot(cx);
 2666                        let selections = editor.selections.all_adjusted_display(&display_map);
 2667                        let pop_state = editor
 2668                            .change_list
 2669                            .last()
 2670                            .map(|previous| {
 2671                                previous.len() == selections.len()
 2672                                    && previous.iter().enumerate().all(|(ix, p)| {
 2673                                        p.to_display_point(&display_map).row()
 2674                                            == selections[ix].head().row()
 2675                                    })
 2676                            })
 2677                            .unwrap_or(false);
 2678                        let new_positions = selections
 2679                            .into_iter()
 2680                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2681                            .collect();
 2682                        editor
 2683                            .change_list
 2684                            .push_to_change_list(pop_state, new_positions);
 2685                    }
 2686                }
 2687                _ => (),
 2688            },
 2689        ));
 2690
 2691        if let Some(dap_store) = editor
 2692            .project
 2693            .as_ref()
 2694            .map(|project| project.read(cx).dap_store())
 2695        {
 2696            let weak_editor = cx.weak_entity();
 2697
 2698            editor
 2699                ._subscriptions
 2700                .push(
 2701                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2702                        let session_entity = cx.entity();
 2703                        weak_editor
 2704                            .update(cx, |editor, cx| {
 2705                                editor._subscriptions.push(
 2706                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2707                                );
 2708                            })
 2709                            .ok();
 2710                    }),
 2711                );
 2712
 2713            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2714                editor
 2715                    ._subscriptions
 2716                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2717            }
 2718        }
 2719
 2720        // skip adding the initial selection to selection history
 2721        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2722        editor.end_selection(window, cx);
 2723        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2724
 2725        editor.scroll_manager.show_scrollbars(window, cx);
 2726        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2727
 2728        if full_mode {
 2729            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2730            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2731
 2732            if editor.git_blame_inline_enabled {
 2733                editor.start_git_blame_inline(false, window, cx);
 2734            }
 2735
 2736            editor.go_to_active_debug_line(window, cx);
 2737
 2738            editor.minimap =
 2739                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2740            editor.colors = Some(LspColorData::new(cx));
 2741            editor.use_document_folding_ranges = true;
 2742            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2743
 2744            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2745                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2746            }
 2747            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2748        }
 2749
 2750        editor
 2751    }
 2752
 2753    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2754        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2755    }
 2756
 2757    pub fn deploy_mouse_context_menu(
 2758        &mut self,
 2759        position: gpui::Point<Pixels>,
 2760        context_menu: Entity<ContextMenu>,
 2761        window: &mut Window,
 2762        cx: &mut Context<Self>,
 2763    ) {
 2764        self.mouse_context_menu = Some(MouseContextMenu::new(
 2765            self,
 2766            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2767            context_menu,
 2768            window,
 2769            cx,
 2770        ));
 2771    }
 2772
 2773    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2774        self.mouse_context_menu
 2775            .as_ref()
 2776            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2777    }
 2778
 2779    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2780        if self
 2781            .selections
 2782            .pending_anchor()
 2783            .is_some_and(|pending_selection| {
 2784                let snapshot = self.buffer().read(cx).snapshot(cx);
 2785                pending_selection.range().includes(range, &snapshot)
 2786            })
 2787        {
 2788            return true;
 2789        }
 2790
 2791        self.selections
 2792            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2793            .into_iter()
 2794            .any(|selection| {
 2795                // This is needed to cover a corner case, if we just check for an existing
 2796                // selection in the fold range, having a cursor at the start of the fold
 2797                // marks it as selected. Non-empty selections don't cause this.
 2798                let length = selection.end - selection.start;
 2799                length > 0
 2800            })
 2801    }
 2802
 2803    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2804        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2805    }
 2806
 2807    fn key_context_internal(
 2808        &self,
 2809        has_active_edit_prediction: bool,
 2810        window: &mut Window,
 2811        cx: &mut App,
 2812    ) -> KeyContext {
 2813        let mut key_context = KeyContext::new_with_defaults();
 2814        key_context.add("Editor");
 2815        let mode = match self.mode {
 2816            EditorMode::SingleLine => "single_line",
 2817            EditorMode::AutoHeight { .. } => "auto_height",
 2818            EditorMode::Minimap { .. } => "minimap",
 2819            EditorMode::Full { .. } => "full",
 2820        };
 2821
 2822        if EditorSettings::jupyter_enabled(cx) {
 2823            key_context.add("jupyter");
 2824        }
 2825
 2826        key_context.set("mode", mode);
 2827        if self.pending_rename.is_some() {
 2828            key_context.add("renaming");
 2829        }
 2830
 2831        if let Some(snippet_stack) = self.snippet_stack.last() {
 2832            key_context.add("in_snippet");
 2833
 2834            if snippet_stack.active_index > 0 {
 2835                key_context.add("has_previous_tabstop");
 2836            }
 2837
 2838            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2839                key_context.add("has_next_tabstop");
 2840            }
 2841        }
 2842
 2843        match self.context_menu.borrow().as_ref() {
 2844            Some(CodeContextMenu::Completions(menu)) => {
 2845                if menu.visible() {
 2846                    key_context.add("menu");
 2847                    key_context.add("showing_completions");
 2848                }
 2849            }
 2850            Some(CodeContextMenu::CodeActions(menu)) => {
 2851                if menu.visible() {
 2852                    key_context.add("menu");
 2853                    key_context.add("showing_code_actions")
 2854                }
 2855            }
 2856            None => {}
 2857        }
 2858
 2859        if self.signature_help_state.has_multiple_signatures() {
 2860            key_context.add("showing_signature_help");
 2861        }
 2862
 2863        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2864        if !self.focus_handle(cx).contains_focused(window, cx)
 2865            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2866        {
 2867            for addon in self.addons.values() {
 2868                addon.extend_key_context(&mut key_context, cx)
 2869            }
 2870        }
 2871
 2872        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2873            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2874                Some(
 2875                    file.full_path(cx)
 2876                        .extension()?
 2877                        .to_string_lossy()
 2878                        .to_lowercase(),
 2879                )
 2880            }) {
 2881                key_context.set("extension", extension);
 2882            }
 2883        } else {
 2884            key_context.add("multibuffer");
 2885        }
 2886
 2887        if has_active_edit_prediction {
 2888            if self.edit_prediction_in_conflict() {
 2889                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2890            } else {
 2891                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2892                key_context.add("copilot_suggestion");
 2893            }
 2894        }
 2895
 2896        if self.selection_mark_mode {
 2897            key_context.add("selection_mode");
 2898        }
 2899
 2900        let disjoint = self.selections.disjoint_anchors();
 2901        let snapshot = self.snapshot(window, cx);
 2902        let snapshot = snapshot.buffer_snapshot();
 2903        if self.mode == EditorMode::SingleLine
 2904            && let [selection] = disjoint
 2905            && selection.start == selection.end
 2906            && selection.end.to_offset(snapshot) == snapshot.len()
 2907        {
 2908            key_context.add("end_of_input");
 2909        }
 2910
 2911        if self.has_any_expanded_diff_hunks(cx) {
 2912            key_context.add("diffs_expanded");
 2913        }
 2914
 2915        key_context
 2916    }
 2917
 2918    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2919        self.last_bounds.as_ref()
 2920    }
 2921
 2922    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2923        if self.mouse_cursor_hidden {
 2924            self.mouse_cursor_hidden = false;
 2925            cx.notify();
 2926        }
 2927    }
 2928
 2929    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2930        let hide_mouse_cursor = match origin {
 2931            HideMouseCursorOrigin::TypingAction => {
 2932                matches!(
 2933                    self.hide_mouse_mode,
 2934                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2935                )
 2936            }
 2937            HideMouseCursorOrigin::MovementAction => {
 2938                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2939            }
 2940        };
 2941        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2942            self.mouse_cursor_hidden = hide_mouse_cursor;
 2943            cx.notify();
 2944        }
 2945    }
 2946
 2947    pub fn edit_prediction_in_conflict(&self) -> bool {
 2948        if !self.show_edit_predictions_in_menu() {
 2949            return false;
 2950        }
 2951
 2952        let showing_completions = self
 2953            .context_menu
 2954            .borrow()
 2955            .as_ref()
 2956            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2957
 2958        showing_completions
 2959            || self.edit_prediction_requires_modifier()
 2960            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2961            // bindings to insert tab characters.
 2962            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2963    }
 2964
 2965    pub fn accept_edit_prediction_keybind(
 2966        &self,
 2967        granularity: EditPredictionGranularity,
 2968        window: &mut Window,
 2969        cx: &mut App,
 2970    ) -> AcceptEditPredictionBinding {
 2971        let key_context = self.key_context_internal(true, window, cx);
 2972        let in_conflict = self.edit_prediction_in_conflict();
 2973
 2974        let bindings =
 2975            match granularity {
 2976                EditPredictionGranularity::Word => window
 2977                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2978                EditPredictionGranularity::Line => window
 2979                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2980                EditPredictionGranularity::Full => {
 2981                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2982                }
 2983            };
 2984
 2985        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2986            !in_conflict
 2987                || binding
 2988                    .keystrokes()
 2989                    .first()
 2990                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2991        }))
 2992    }
 2993
 2994    pub fn new_file(
 2995        workspace: &mut Workspace,
 2996        _: &workspace::NewFile,
 2997        window: &mut Window,
 2998        cx: &mut Context<Workspace>,
 2999    ) {
 3000        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 3001            "Failed to create buffer",
 3002            window,
 3003            cx,
 3004            |e, _, _| match e.error_code() {
 3005                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3006                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3007                e.error_tag("required").unwrap_or("the latest version")
 3008            )),
 3009                _ => None,
 3010            },
 3011        );
 3012    }
 3013
 3014    pub fn new_in_workspace(
 3015        workspace: &mut Workspace,
 3016        window: &mut Window,
 3017        cx: &mut Context<Workspace>,
 3018    ) -> Task<Result<Entity<Editor>>> {
 3019        let project = workspace.project().clone();
 3020        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3021
 3022        cx.spawn_in(window, async move |workspace, cx| {
 3023            let buffer = create.await?;
 3024            workspace.update_in(cx, |workspace, window, cx| {
 3025                let editor =
 3026                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 3027                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 3028                editor
 3029            })
 3030        })
 3031    }
 3032
 3033    fn new_file_vertical(
 3034        workspace: &mut Workspace,
 3035        _: &workspace::NewFileSplitVertical,
 3036        window: &mut Window,
 3037        cx: &mut Context<Workspace>,
 3038    ) {
 3039        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3040    }
 3041
 3042    fn new_file_horizontal(
 3043        workspace: &mut Workspace,
 3044        _: &workspace::NewFileSplitHorizontal,
 3045        window: &mut Window,
 3046        cx: &mut Context<Workspace>,
 3047    ) {
 3048        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3049    }
 3050
 3051    fn new_file_split(
 3052        workspace: &mut Workspace,
 3053        action: &workspace::NewFileSplit,
 3054        window: &mut Window,
 3055        cx: &mut Context<Workspace>,
 3056    ) {
 3057        Self::new_file_in_direction(workspace, action.0, window, cx)
 3058    }
 3059
 3060    fn new_file_in_direction(
 3061        workspace: &mut Workspace,
 3062        direction: SplitDirection,
 3063        window: &mut Window,
 3064        cx: &mut Context<Workspace>,
 3065    ) {
 3066        let project = workspace.project().clone();
 3067        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3068
 3069        cx.spawn_in(window, async move |workspace, cx| {
 3070            let buffer = create.await?;
 3071            workspace.update_in(cx, move |workspace, window, cx| {
 3072                workspace.split_item(
 3073                    direction,
 3074                    Box::new(
 3075                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3076                    ),
 3077                    window,
 3078                    cx,
 3079                )
 3080            })?;
 3081            anyhow::Ok(())
 3082        })
 3083        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3084            match e.error_code() {
 3085                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3086                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3087                e.error_tag("required").unwrap_or("the latest version")
 3088            )),
 3089                _ => None,
 3090            }
 3091        });
 3092    }
 3093
 3094    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3095        self.leader_id
 3096    }
 3097
 3098    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3099        &self.buffer
 3100    }
 3101
 3102    pub fn project(&self) -> Option<&Entity<Project>> {
 3103        self.project.as_ref()
 3104    }
 3105
 3106    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3107        self.workspace.as_ref()?.0.upgrade()
 3108    }
 3109
 3110    /// Returns the workspace serialization ID if this editor should be serialized.
 3111    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3112        self.workspace
 3113            .as_ref()
 3114            .filter(|_| self.should_serialize_buffer())
 3115            .and_then(|workspace| workspace.1)
 3116    }
 3117
 3118    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3119        self.buffer().read(cx).title(cx)
 3120    }
 3121
 3122    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3123        let git_blame_gutter_max_author_length = self
 3124            .render_git_blame_gutter(cx)
 3125            .then(|| {
 3126                if let Some(blame) = self.blame.as_ref() {
 3127                    let max_author_length =
 3128                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3129                    Some(max_author_length)
 3130                } else {
 3131                    None
 3132                }
 3133            })
 3134            .flatten();
 3135
 3136        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3137
 3138        EditorSnapshot {
 3139            mode: self.mode.clone(),
 3140            show_gutter: self.show_gutter,
 3141            offset_content: self.offset_content,
 3142            show_line_numbers: self.show_line_numbers,
 3143            number_deleted_lines: self.number_deleted_lines,
 3144            show_git_diff_gutter: self.show_git_diff_gutter,
 3145            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3146            show_code_actions: self.show_code_actions,
 3147            show_runnables: self.show_runnables,
 3148            show_breakpoints: self.show_breakpoints,
 3149            git_blame_gutter_max_author_length,
 3150            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3151            display_snapshot,
 3152            placeholder_display_snapshot: self
 3153                .placeholder_display_map
 3154                .as_ref()
 3155                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3156            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3157            is_focused: self.focus_handle.is_focused(window),
 3158            current_line_highlight: self
 3159                .current_line_highlight
 3160                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3161            gutter_hovered: self.gutter_hovered,
 3162        }
 3163    }
 3164
 3165    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3166        self.buffer.read(cx).language_at(point, cx)
 3167    }
 3168
 3169    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3170        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3171    }
 3172
 3173    pub fn active_excerpt(
 3174        &self,
 3175        cx: &App,
 3176    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3177        self.buffer
 3178            .read(cx)
 3179            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3180    }
 3181
 3182    pub fn mode(&self) -> &EditorMode {
 3183        &self.mode
 3184    }
 3185
 3186    pub fn set_mode(&mut self, mode: EditorMode) {
 3187        self.mode = mode;
 3188    }
 3189
 3190    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3191        self.collaboration_hub.as_deref()
 3192    }
 3193
 3194    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3195        self.collaboration_hub = Some(hub);
 3196    }
 3197
 3198    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3199        self.in_project_search = in_project_search;
 3200    }
 3201
 3202    pub fn set_custom_context_menu(
 3203        &mut self,
 3204        f: impl 'static
 3205        + Fn(
 3206            &mut Self,
 3207            DisplayPoint,
 3208            &mut Window,
 3209            &mut Context<Self>,
 3210        ) -> Option<Entity<ui::ContextMenu>>,
 3211    ) {
 3212        self.custom_context_menu = Some(Box::new(f))
 3213    }
 3214
 3215    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3216        self.completion_provider = provider;
 3217    }
 3218
 3219    #[cfg(any(test, feature = "test-support"))]
 3220    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3221        self.completion_provider.clone()
 3222    }
 3223
 3224    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3225        self.semantics_provider.clone()
 3226    }
 3227
 3228    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3229        self.semantics_provider = provider;
 3230    }
 3231
 3232    pub fn set_edit_prediction_provider<T>(
 3233        &mut self,
 3234        provider: Option<Entity<T>>,
 3235        window: &mut Window,
 3236        cx: &mut Context<Self>,
 3237    ) where
 3238        T: EditPredictionDelegate,
 3239    {
 3240        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3241            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3242                if this.focus_handle.is_focused(window) {
 3243                    this.update_visible_edit_prediction(window, cx);
 3244                }
 3245            }),
 3246            provider: Arc::new(provider),
 3247        });
 3248        self.update_edit_prediction_settings(cx);
 3249        self.refresh_edit_prediction(false, false, window, cx);
 3250    }
 3251
 3252    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3253        self.placeholder_display_map
 3254            .as_ref()
 3255            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3256    }
 3257
 3258    pub fn set_placeholder_text(
 3259        &mut self,
 3260        placeholder_text: &str,
 3261        window: &mut Window,
 3262        cx: &mut Context<Self>,
 3263    ) {
 3264        let multibuffer = cx
 3265            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3266
 3267        let style = window.text_style();
 3268
 3269        self.placeholder_display_map = Some(cx.new(|cx| {
 3270            DisplayMap::new(
 3271                multibuffer,
 3272                style.font(),
 3273                style.font_size.to_pixels(window.rem_size()),
 3274                None,
 3275                FILE_HEADER_HEIGHT,
 3276                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3277                Default::default(),
 3278                DiagnosticSeverity::Off,
 3279                cx,
 3280            )
 3281        }));
 3282        cx.notify();
 3283    }
 3284
 3285    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3286        self.cursor_shape = cursor_shape;
 3287
 3288        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3289        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3290
 3291        cx.notify();
 3292    }
 3293
 3294    pub fn cursor_shape(&self) -> CursorShape {
 3295        self.cursor_shape
 3296    }
 3297
 3298    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3299        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3300    }
 3301
 3302    pub fn set_current_line_highlight(
 3303        &mut self,
 3304        current_line_highlight: Option<CurrentLineHighlight>,
 3305    ) {
 3306        self.current_line_highlight = current_line_highlight;
 3307    }
 3308
 3309    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3310        self.collapse_matches = collapse_matches;
 3311    }
 3312
 3313    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3314        if self.collapse_matches {
 3315            return range.start..range.start;
 3316        }
 3317        range.clone()
 3318    }
 3319
 3320    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3321        self.display_map.read(cx).clip_at_line_ends
 3322    }
 3323
 3324    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3325        if self.display_map.read(cx).clip_at_line_ends != clip {
 3326            self.display_map
 3327                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3328        }
 3329    }
 3330
 3331    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3332        self.input_enabled = input_enabled;
 3333    }
 3334
 3335    pub fn set_edit_predictions_hidden_for_vim_mode(
 3336        &mut self,
 3337        hidden: bool,
 3338        window: &mut Window,
 3339        cx: &mut Context<Self>,
 3340    ) {
 3341        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3342            self.edit_predictions_hidden_for_vim_mode = hidden;
 3343            if hidden {
 3344                self.update_visible_edit_prediction(window, cx);
 3345            } else {
 3346                self.refresh_edit_prediction(true, false, window, cx);
 3347            }
 3348        }
 3349    }
 3350
 3351    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3352        self.menu_edit_predictions_policy = value;
 3353    }
 3354
 3355    pub fn set_autoindent(&mut self, autoindent: bool) {
 3356        if autoindent {
 3357            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3358        } else {
 3359            self.autoindent_mode = None;
 3360        }
 3361    }
 3362
 3363    pub fn capability(&self, cx: &App) -> Capability {
 3364        if self.read_only {
 3365            Capability::ReadOnly
 3366        } else {
 3367            self.buffer.read(cx).capability()
 3368        }
 3369    }
 3370
 3371    pub fn read_only(&self, cx: &App) -> bool {
 3372        self.read_only || self.buffer.read(cx).read_only()
 3373    }
 3374
 3375    pub fn set_read_only(&mut self, read_only: bool) {
 3376        self.read_only = read_only;
 3377    }
 3378
 3379    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3380        self.use_autoclose = autoclose;
 3381    }
 3382
 3383    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3384        self.use_auto_surround = auto_surround;
 3385    }
 3386
 3387    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3388        self.auto_replace_emoji_shortcode = auto_replace;
 3389    }
 3390
 3391    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3392        self.buffer_serialization = should_serialize.then(|| {
 3393            BufferSerialization::new(
 3394                ProjectSettings::get_global(cx)
 3395                    .session
 3396                    .restore_unsaved_buffers,
 3397            )
 3398        })
 3399    }
 3400
 3401    fn should_serialize_buffer(&self) -> bool {
 3402        self.buffer_serialization.is_some()
 3403    }
 3404
 3405    pub fn toggle_edit_predictions(
 3406        &mut self,
 3407        _: &ToggleEditPrediction,
 3408        window: &mut Window,
 3409        cx: &mut Context<Self>,
 3410    ) {
 3411        if self.show_edit_predictions_override.is_some() {
 3412            self.set_show_edit_predictions(None, window, cx);
 3413        } else {
 3414            let show_edit_predictions = !self.edit_predictions_enabled();
 3415            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3416        }
 3417    }
 3418
 3419    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3420        self.show_completions_on_input_override = show_completions_on_input;
 3421    }
 3422
 3423    pub fn set_show_edit_predictions(
 3424        &mut self,
 3425        show_edit_predictions: Option<bool>,
 3426        window: &mut Window,
 3427        cx: &mut Context<Self>,
 3428    ) {
 3429        self.show_edit_predictions_override = show_edit_predictions;
 3430        self.update_edit_prediction_settings(cx);
 3431
 3432        if let Some(false) = show_edit_predictions {
 3433            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3434        } else {
 3435            self.refresh_edit_prediction(false, true, window, cx);
 3436        }
 3437    }
 3438
 3439    fn edit_predictions_disabled_in_scope(
 3440        &self,
 3441        buffer: &Entity<Buffer>,
 3442        buffer_position: language::Anchor,
 3443        cx: &App,
 3444    ) -> bool {
 3445        let snapshot = buffer.read(cx).snapshot();
 3446        let settings = snapshot.settings_at(buffer_position, cx);
 3447
 3448        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3449            return false;
 3450        };
 3451
 3452        scope.override_name().is_some_and(|scope_name| {
 3453            settings
 3454                .edit_predictions_disabled_in
 3455                .iter()
 3456                .any(|s| s == scope_name)
 3457        })
 3458    }
 3459
 3460    pub fn set_use_modal_editing(&mut self, to: bool) {
 3461        self.use_modal_editing = to;
 3462    }
 3463
 3464    pub fn use_modal_editing(&self) -> bool {
 3465        self.use_modal_editing
 3466    }
 3467
 3468    fn selections_did_change(
 3469        &mut self,
 3470        local: bool,
 3471        old_cursor_position: &Anchor,
 3472        effects: SelectionEffects,
 3473        window: &mut Window,
 3474        cx: &mut Context<Self>,
 3475    ) {
 3476        window.invalidate_character_coordinates();
 3477
 3478        // Copy selections to primary selection buffer
 3479        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3480        if local {
 3481            let selections = self
 3482                .selections
 3483                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3484            let buffer_handle = self.buffer.read(cx).read(cx);
 3485
 3486            let mut text = String::new();
 3487            for (index, selection) in selections.iter().enumerate() {
 3488                let text_for_selection = buffer_handle
 3489                    .text_for_range(selection.start..selection.end)
 3490                    .collect::<String>();
 3491
 3492                text.push_str(&text_for_selection);
 3493                if index != selections.len() - 1 {
 3494                    text.push('\n');
 3495                }
 3496            }
 3497
 3498            if !text.is_empty() {
 3499                cx.write_to_primary(ClipboardItem::new_string(text));
 3500            }
 3501        }
 3502
 3503        let selection_anchors = self.selections.disjoint_anchors_arc();
 3504
 3505        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3506            self.buffer.update(cx, |buffer, cx| {
 3507                buffer.set_active_selections(
 3508                    &selection_anchors,
 3509                    self.selections.line_mode(),
 3510                    self.cursor_shape,
 3511                    cx,
 3512                )
 3513            });
 3514        }
 3515        let display_map = self
 3516            .display_map
 3517            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3518        let buffer = display_map.buffer_snapshot();
 3519        if self.selections.count() == 1 {
 3520            self.add_selections_state = None;
 3521        }
 3522        self.select_next_state = None;
 3523        self.select_prev_state = None;
 3524        self.select_syntax_node_history.try_clear();
 3525        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3526        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3527        self.take_rename(false, window, cx);
 3528
 3529        let newest_selection = self.selections.newest_anchor();
 3530        let new_cursor_position = newest_selection.head();
 3531        let selection_start = newest_selection.start;
 3532
 3533        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3534            self.push_to_nav_history(
 3535                *old_cursor_position,
 3536                Some(new_cursor_position.to_point(buffer)),
 3537                false,
 3538                effects.nav_history == Some(true),
 3539                cx,
 3540            );
 3541        }
 3542
 3543        if local {
 3544            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3545                self.register_buffer(buffer_id, cx);
 3546            }
 3547
 3548            let mut context_menu = self.context_menu.borrow_mut();
 3549            let completion_menu = match context_menu.as_ref() {
 3550                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3551                Some(CodeContextMenu::CodeActions(_)) => {
 3552                    *context_menu = None;
 3553                    None
 3554                }
 3555                None => None,
 3556            };
 3557            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3558            drop(context_menu);
 3559
 3560            if effects.completions
 3561                && let Some(completion_position) = completion_position
 3562            {
 3563                let start_offset = selection_start.to_offset(buffer);
 3564                let position_matches = start_offset == completion_position.to_offset(buffer);
 3565                let continue_showing = if let Some((snap, ..)) =
 3566                    buffer.point_to_buffer_offset(completion_position)
 3567                    && !snap.capability.editable()
 3568                {
 3569                    false
 3570                } else if position_matches {
 3571                    if self.snippet_stack.is_empty() {
 3572                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3573                            == Some(CharKind::Word)
 3574                    } else {
 3575                        // Snippet choices can be shown even when the cursor is in whitespace.
 3576                        // Dismissing the menu with actions like backspace is handled by
 3577                        // invalidation regions.
 3578                        true
 3579                    }
 3580                } else {
 3581                    false
 3582                };
 3583
 3584                if continue_showing {
 3585                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3586                } else {
 3587                    self.hide_context_menu(window, cx);
 3588                }
 3589            }
 3590
 3591            hide_hover(self, cx);
 3592
 3593            if old_cursor_position.to_display_point(&display_map).row()
 3594                != new_cursor_position.to_display_point(&display_map).row()
 3595            {
 3596                self.available_code_actions.take();
 3597            }
 3598            self.refresh_code_actions(window, cx);
 3599            self.refresh_document_highlights(cx);
 3600            refresh_linked_ranges(self, window, cx);
 3601
 3602            self.refresh_selected_text_highlights(false, window, cx);
 3603            self.refresh_matching_bracket_highlights(window, cx);
 3604            self.refresh_outline_symbols(cx);
 3605            self.update_visible_edit_prediction(window, cx);
 3606            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3607            self.inline_blame_popover.take();
 3608            if self.git_blame_inline_enabled {
 3609                self.start_inline_blame_timer(window, cx);
 3610            }
 3611        }
 3612
 3613        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3614
 3615        if local && !self.suppress_selection_callback {
 3616            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3617                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3618                callback(cursor_position, window, cx);
 3619            }
 3620        }
 3621
 3622        cx.emit(EditorEvent::SelectionsChanged { local });
 3623
 3624        let selections = &self.selections.disjoint_anchors_arc();
 3625        if selections.len() == 1 {
 3626            cx.emit(SearchEvent::ActiveMatchChanged)
 3627        }
 3628        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3629            let inmemory_selections = selections
 3630                .iter()
 3631                .map(|s| {
 3632                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3633                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3634                })
 3635                .collect();
 3636            self.update_restoration_data(cx, |data| {
 3637                data.selections = inmemory_selections;
 3638            });
 3639
 3640            if WorkspaceSettings::get(None, cx).restore_on_startup
 3641                != RestoreOnStartupBehavior::EmptyTab
 3642                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3643            {
 3644                let snapshot = self.buffer().read(cx).snapshot(cx);
 3645                let selections = selections.clone();
 3646                let background_executor = cx.background_executor().clone();
 3647                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3648                self.serialize_selections = cx.background_spawn(async move {
 3649                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3650                    let db_selections = selections
 3651                        .iter()
 3652                        .map(|selection| {
 3653                            (
 3654                                selection.start.to_offset(&snapshot).0,
 3655                                selection.end.to_offset(&snapshot).0,
 3656                            )
 3657                        })
 3658                        .collect();
 3659
 3660                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3661                        .await
 3662                        .with_context(|| {
 3663                            format!(
 3664                                "persisting editor selections for editor {editor_id}, \
 3665                                workspace {workspace_id:?}"
 3666                            )
 3667                        })
 3668                        .log_err();
 3669                });
 3670            }
 3671        }
 3672
 3673        cx.notify();
 3674    }
 3675
 3676    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3677        use text::ToOffset as _;
 3678        use text::ToPoint as _;
 3679
 3680        if self.mode.is_minimap()
 3681            || WorkspaceSettings::get(None, cx).restore_on_startup
 3682                == RestoreOnStartupBehavior::EmptyTab
 3683        {
 3684            return;
 3685        }
 3686
 3687        if !self.buffer().read(cx).is_singleton() {
 3688            return;
 3689        }
 3690
 3691        let display_snapshot = self
 3692            .display_map
 3693            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3694        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3695            return;
 3696        };
 3697        let inmemory_folds = display_snapshot
 3698            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3699            .map(|fold| {
 3700                fold.range.start.text_anchor.to_point(&snapshot)
 3701                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3702            })
 3703            .collect();
 3704        self.update_restoration_data(cx, |data| {
 3705            data.folds = inmemory_folds;
 3706        });
 3707
 3708        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3709            return;
 3710        };
 3711        let background_executor = cx.background_executor().clone();
 3712        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3713        const FINGERPRINT_LEN: usize = 32;
 3714        let db_folds = display_snapshot
 3715            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3716            .map(|fold| {
 3717                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3718                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3719
 3720                // Extract fingerprints - content at fold boundaries for validation on restore
 3721                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3722                // content that might change independently.
 3723                // start_fp: first min(32, fold_len) bytes of fold content
 3724                // end_fp: last min(32, fold_len) bytes of fold content
 3725                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3726                let fold_len = end - start;
 3727                let start_fp_end = snapshot
 3728                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3729                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3730                let end_fp_start = snapshot
 3731                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3732                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3733
 3734                (start, end, start_fp, end_fp)
 3735            })
 3736            .collect::<Vec<_>>();
 3737        self.serialize_folds = cx.background_spawn(async move {
 3738            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3739            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3740                .await
 3741                .with_context(|| {
 3742                    format!(
 3743                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3744                    )
 3745                })
 3746                .log_err();
 3747        });
 3748    }
 3749
 3750    pub fn sync_selections(
 3751        &mut self,
 3752        other: Entity<Editor>,
 3753        cx: &mut Context<Self>,
 3754    ) -> gpui::Subscription {
 3755        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3756        if !other_selections.is_empty() {
 3757            self.selections
 3758                .change_with(&self.display_snapshot(cx), |selections| {
 3759                    selections.select_anchors(other_selections);
 3760                });
 3761        }
 3762
 3763        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3764            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3765                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3766                if other_selections.is_empty() {
 3767                    return;
 3768                }
 3769                let snapshot = this.display_snapshot(cx);
 3770                this.selections.change_with(&snapshot, |selections| {
 3771                    selections.select_anchors(other_selections);
 3772                });
 3773            }
 3774        });
 3775
 3776        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3777            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3778                let these_selections = this.selections.disjoint_anchors().to_vec();
 3779                if these_selections.is_empty() {
 3780                    return;
 3781                }
 3782                other.update(cx, |other_editor, cx| {
 3783                    let snapshot = other_editor.display_snapshot(cx);
 3784                    other_editor
 3785                        .selections
 3786                        .change_with(&snapshot, |selections| {
 3787                            selections.select_anchors(these_selections);
 3788                        })
 3789                });
 3790            }
 3791        });
 3792
 3793        Subscription::join(other_subscription, this_subscription)
 3794    }
 3795
 3796    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3797        if self.buffer().read(cx).is_singleton() {
 3798            return;
 3799        }
 3800        let snapshot = self.buffer.read(cx).snapshot(cx);
 3801        let buffer_ids: HashSet<BufferId> = self
 3802            .selections
 3803            .disjoint_anchor_ranges()
 3804            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3805            .collect();
 3806        for buffer_id in buffer_ids {
 3807            self.unfold_buffer(buffer_id, cx);
 3808        }
 3809    }
 3810
 3811    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3812    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3813    /// effects of selection change occur at the end of the transaction.
 3814    pub fn change_selections<R>(
 3815        &mut self,
 3816        effects: SelectionEffects,
 3817        window: &mut Window,
 3818        cx: &mut Context<Self>,
 3819        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3820    ) -> R {
 3821        let snapshot = self.display_snapshot(cx);
 3822        if let Some(state) = &mut self.deferred_selection_effects_state {
 3823            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3824            state.effects.completions = effects.completions;
 3825            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3826            let (changed, result) = self.selections.change_with(&snapshot, change);
 3827            state.changed |= changed;
 3828            return result;
 3829        }
 3830        let mut state = DeferredSelectionEffectsState {
 3831            changed: false,
 3832            effects,
 3833            old_cursor_position: self.selections.newest_anchor().head(),
 3834            history_entry: SelectionHistoryEntry {
 3835                selections: self.selections.disjoint_anchors_arc(),
 3836                select_next_state: self.select_next_state.clone(),
 3837                select_prev_state: self.select_prev_state.clone(),
 3838                add_selections_state: self.add_selections_state.clone(),
 3839            },
 3840        };
 3841        let (changed, result) = self.selections.change_with(&snapshot, change);
 3842        state.changed = state.changed || changed;
 3843        if self.defer_selection_effects {
 3844            self.deferred_selection_effects_state = Some(state);
 3845        } else {
 3846            self.apply_selection_effects(state, window, cx);
 3847        }
 3848        result
 3849    }
 3850
 3851    /// Defers the effects of selection change, so that the effects of multiple calls to
 3852    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3853    /// to selection history and the state of popovers based on selection position aren't
 3854    /// erroneously updated.
 3855    pub fn with_selection_effects_deferred<R>(
 3856        &mut self,
 3857        window: &mut Window,
 3858        cx: &mut Context<Self>,
 3859        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3860    ) -> R {
 3861        let already_deferred = self.defer_selection_effects;
 3862        self.defer_selection_effects = true;
 3863        let result = update(self, window, cx);
 3864        if !already_deferred {
 3865            self.defer_selection_effects = false;
 3866            if let Some(state) = self.deferred_selection_effects_state.take() {
 3867                self.apply_selection_effects(state, window, cx);
 3868            }
 3869        }
 3870        result
 3871    }
 3872
 3873    fn apply_selection_effects(
 3874        &mut self,
 3875        state: DeferredSelectionEffectsState,
 3876        window: &mut Window,
 3877        cx: &mut Context<Self>,
 3878    ) {
 3879        if state.changed {
 3880            self.selection_history.push(state.history_entry);
 3881
 3882            if let Some(autoscroll) = state.effects.scroll {
 3883                self.request_autoscroll(autoscroll, cx);
 3884            }
 3885
 3886            let old_cursor_position = &state.old_cursor_position;
 3887
 3888            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3889
 3890            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3891                self.show_signature_help_auto(window, cx);
 3892            }
 3893        }
 3894    }
 3895
 3896    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3897    where
 3898        I: IntoIterator<Item = (Range<S>, T)>,
 3899        S: ToOffset,
 3900        T: Into<Arc<str>>,
 3901    {
 3902        if self.read_only(cx) {
 3903            return;
 3904        }
 3905
 3906        self.buffer
 3907            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3908    }
 3909
 3910    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3911    where
 3912        I: IntoIterator<Item = (Range<S>, T)>,
 3913        S: ToOffset,
 3914        T: Into<Arc<str>>,
 3915    {
 3916        if self.read_only(cx) {
 3917            return;
 3918        }
 3919
 3920        self.buffer.update(cx, |buffer, cx| {
 3921            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3922        });
 3923    }
 3924
 3925    pub fn edit_with_block_indent<I, S, T>(
 3926        &mut self,
 3927        edits: I,
 3928        original_indent_columns: Vec<Option<u32>>,
 3929        cx: &mut Context<Self>,
 3930    ) where
 3931        I: IntoIterator<Item = (Range<S>, T)>,
 3932        S: ToOffset,
 3933        T: Into<Arc<str>>,
 3934    {
 3935        if self.read_only(cx) {
 3936            return;
 3937        }
 3938
 3939        self.buffer.update(cx, |buffer, cx| {
 3940            buffer.edit(
 3941                edits,
 3942                Some(AutoindentMode::Block {
 3943                    original_indent_columns,
 3944                }),
 3945                cx,
 3946            )
 3947        });
 3948    }
 3949
 3950    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3951        self.hide_context_menu(window, cx);
 3952
 3953        match phase {
 3954            SelectPhase::Begin {
 3955                position,
 3956                add,
 3957                click_count,
 3958            } => self.begin_selection(position, add, click_count, window, cx),
 3959            SelectPhase::BeginColumnar {
 3960                position,
 3961                goal_column,
 3962                reset,
 3963                mode,
 3964            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3965            SelectPhase::Extend {
 3966                position,
 3967                click_count,
 3968            } => self.extend_selection(position, click_count, window, cx),
 3969            SelectPhase::Update {
 3970                position,
 3971                goal_column,
 3972                scroll_delta,
 3973            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3974            SelectPhase::End => self.end_selection(window, cx),
 3975        }
 3976    }
 3977
 3978    fn extend_selection(
 3979        &mut self,
 3980        position: DisplayPoint,
 3981        click_count: usize,
 3982        window: &mut Window,
 3983        cx: &mut Context<Self>,
 3984    ) {
 3985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3986        let tail = self
 3987            .selections
 3988            .newest::<MultiBufferOffset>(&display_map)
 3989            .tail();
 3990        let click_count = click_count.max(match self.selections.select_mode() {
 3991            SelectMode::Character => 1,
 3992            SelectMode::Word(_) => 2,
 3993            SelectMode::Line(_) => 3,
 3994            SelectMode::All => 4,
 3995        });
 3996        self.begin_selection(position, false, click_count, window, cx);
 3997
 3998        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3999
 4000        let current_selection = match self.selections.select_mode() {
 4001            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4002            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4003        };
 4004
 4005        let mut pending_selection = self
 4006            .selections
 4007            .pending_anchor()
 4008            .cloned()
 4009            .expect("extend_selection not called with pending selection");
 4010
 4011        if pending_selection
 4012            .start
 4013            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4014            == Ordering::Greater
 4015        {
 4016            pending_selection.start = current_selection.start;
 4017        }
 4018        if pending_selection
 4019            .end
 4020            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4021            == Ordering::Less
 4022        {
 4023            pending_selection.end = current_selection.end;
 4024            pending_selection.reversed = true;
 4025        }
 4026
 4027        let mut pending_mode = self.selections.pending_mode().unwrap();
 4028        match &mut pending_mode {
 4029            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4030            _ => {}
 4031        }
 4032
 4033        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4034            SelectionEffects::scroll(Autoscroll::fit())
 4035        } else {
 4036            SelectionEffects::no_scroll()
 4037        };
 4038
 4039        self.change_selections(effects, window, cx, |s| {
 4040            s.set_pending(pending_selection.clone(), pending_mode);
 4041            s.set_is_extending(true);
 4042        });
 4043    }
 4044
 4045    fn begin_selection(
 4046        &mut self,
 4047        position: DisplayPoint,
 4048        add: bool,
 4049        click_count: usize,
 4050        window: &mut Window,
 4051        cx: &mut Context<Self>,
 4052    ) {
 4053        if !self.focus_handle.is_focused(window) {
 4054            self.last_focused_descendant = None;
 4055            window.focus(&self.focus_handle, cx);
 4056        }
 4057
 4058        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4059        let buffer = display_map.buffer_snapshot();
 4060        let position = display_map.clip_point(position, Bias::Left);
 4061
 4062        let start;
 4063        let end;
 4064        let mode;
 4065        let mut auto_scroll;
 4066        match click_count {
 4067            1 => {
 4068                start = buffer.anchor_before(position.to_point(&display_map));
 4069                end = start;
 4070                mode = SelectMode::Character;
 4071                auto_scroll = true;
 4072            }
 4073            2 => {
 4074                let position = display_map
 4075                    .clip_point(position, Bias::Left)
 4076                    .to_offset(&display_map, Bias::Left);
 4077                let (range, _) = buffer.surrounding_word(position, None);
 4078                start = buffer.anchor_before(range.start);
 4079                end = buffer.anchor_before(range.end);
 4080                mode = SelectMode::Word(start..end);
 4081                auto_scroll = true;
 4082            }
 4083            3 => {
 4084                let position = display_map
 4085                    .clip_point(position, Bias::Left)
 4086                    .to_point(&display_map);
 4087                let line_start = display_map.prev_line_boundary(position).0;
 4088                let next_line_start = buffer.clip_point(
 4089                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4090                    Bias::Left,
 4091                );
 4092                start = buffer.anchor_before(line_start);
 4093                end = buffer.anchor_before(next_line_start);
 4094                mode = SelectMode::Line(start..end);
 4095                auto_scroll = true;
 4096            }
 4097            _ => {
 4098                start = buffer.anchor_before(MultiBufferOffset(0));
 4099                end = buffer.anchor_before(buffer.len());
 4100                mode = SelectMode::All;
 4101                auto_scroll = false;
 4102            }
 4103        }
 4104        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4105
 4106        let point_to_delete: Option<usize> = {
 4107            let selected_points: Vec<Selection<Point>> =
 4108                self.selections.disjoint_in_range(start..end, &display_map);
 4109
 4110            if !add || click_count > 1 {
 4111                None
 4112            } else if !selected_points.is_empty() {
 4113                Some(selected_points[0].id)
 4114            } else {
 4115                let clicked_point_already_selected =
 4116                    self.selections.disjoint_anchors().iter().find(|selection| {
 4117                        selection.start.to_point(buffer) == start.to_point(buffer)
 4118                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4119                    });
 4120
 4121                clicked_point_already_selected.map(|selection| selection.id)
 4122            }
 4123        };
 4124
 4125        let selections_count = self.selections.count();
 4126        let effects = if auto_scroll {
 4127            SelectionEffects::default()
 4128        } else {
 4129            SelectionEffects::no_scroll()
 4130        };
 4131
 4132        self.change_selections(effects, window, cx, |s| {
 4133            if let Some(point_to_delete) = point_to_delete {
 4134                s.delete(point_to_delete);
 4135
 4136                if selections_count == 1 {
 4137                    s.set_pending_anchor_range(start..end, mode);
 4138                }
 4139            } else {
 4140                if !add {
 4141                    s.clear_disjoint();
 4142                }
 4143
 4144                s.set_pending_anchor_range(start..end, mode);
 4145            }
 4146        });
 4147    }
 4148
 4149    fn begin_columnar_selection(
 4150        &mut self,
 4151        position: DisplayPoint,
 4152        goal_column: u32,
 4153        reset: bool,
 4154        mode: ColumnarMode,
 4155        window: &mut Window,
 4156        cx: &mut Context<Self>,
 4157    ) {
 4158        if !self.focus_handle.is_focused(window) {
 4159            self.last_focused_descendant = None;
 4160            window.focus(&self.focus_handle, cx);
 4161        }
 4162
 4163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4164
 4165        if reset {
 4166            let pointer_position = display_map
 4167                .buffer_snapshot()
 4168                .anchor_before(position.to_point(&display_map));
 4169
 4170            self.change_selections(
 4171                SelectionEffects::scroll(Autoscroll::newest()),
 4172                window,
 4173                cx,
 4174                |s| {
 4175                    s.clear_disjoint();
 4176                    s.set_pending_anchor_range(
 4177                        pointer_position..pointer_position,
 4178                        SelectMode::Character,
 4179                    );
 4180                },
 4181            );
 4182        };
 4183
 4184        let tail = self.selections.newest::<Point>(&display_map).tail();
 4185        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4186        self.columnar_selection_state = match mode {
 4187            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4188                selection_tail: selection_anchor,
 4189                display_point: if reset {
 4190                    if position.column() != goal_column {
 4191                        Some(DisplayPoint::new(position.row(), goal_column))
 4192                    } else {
 4193                        None
 4194                    }
 4195                } else {
 4196                    None
 4197                },
 4198            }),
 4199            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4200                selection_tail: selection_anchor,
 4201            }),
 4202        };
 4203
 4204        if !reset {
 4205            self.select_columns(position, goal_column, &display_map, window, cx);
 4206        }
 4207    }
 4208
 4209    fn update_selection(
 4210        &mut self,
 4211        position: DisplayPoint,
 4212        goal_column: u32,
 4213        scroll_delta: gpui::Point<f32>,
 4214        window: &mut Window,
 4215        cx: &mut Context<Self>,
 4216    ) {
 4217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4218
 4219        if self.columnar_selection_state.is_some() {
 4220            self.select_columns(position, goal_column, &display_map, window, cx);
 4221        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4222            let buffer = display_map.buffer_snapshot();
 4223            let head;
 4224            let tail;
 4225            let mode = self.selections.pending_mode().unwrap();
 4226            match &mode {
 4227                SelectMode::Character => {
 4228                    head = position.to_point(&display_map);
 4229                    tail = pending.tail().to_point(buffer);
 4230                }
 4231                SelectMode::Word(original_range) => {
 4232                    let offset = display_map
 4233                        .clip_point(position, Bias::Left)
 4234                        .to_offset(&display_map, Bias::Left);
 4235                    let original_range = original_range.to_offset(buffer);
 4236
 4237                    let head_offset = if buffer.is_inside_word(offset, None)
 4238                        || original_range.contains(&offset)
 4239                    {
 4240                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4241                        if word_range.start < original_range.start {
 4242                            word_range.start
 4243                        } else {
 4244                            word_range.end
 4245                        }
 4246                    } else {
 4247                        offset
 4248                    };
 4249
 4250                    head = head_offset.to_point(buffer);
 4251                    if head_offset <= original_range.start {
 4252                        tail = original_range.end.to_point(buffer);
 4253                    } else {
 4254                        tail = original_range.start.to_point(buffer);
 4255                    }
 4256                }
 4257                SelectMode::Line(original_range) => {
 4258                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4259
 4260                    let position = display_map
 4261                        .clip_point(position, Bias::Left)
 4262                        .to_point(&display_map);
 4263                    let line_start = display_map.prev_line_boundary(position).0;
 4264                    let next_line_start = buffer.clip_point(
 4265                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4266                        Bias::Left,
 4267                    );
 4268
 4269                    if line_start < original_range.start {
 4270                        head = line_start
 4271                    } else {
 4272                        head = next_line_start
 4273                    }
 4274
 4275                    if head <= original_range.start {
 4276                        tail = original_range.end;
 4277                    } else {
 4278                        tail = original_range.start;
 4279                    }
 4280                }
 4281                SelectMode::All => {
 4282                    return;
 4283                }
 4284            };
 4285
 4286            if head < tail {
 4287                pending.start = buffer.anchor_before(head);
 4288                pending.end = buffer.anchor_before(tail);
 4289                pending.reversed = true;
 4290            } else {
 4291                pending.start = buffer.anchor_before(tail);
 4292                pending.end = buffer.anchor_before(head);
 4293                pending.reversed = false;
 4294            }
 4295
 4296            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4297                s.set_pending(pending.clone(), mode);
 4298            });
 4299        } else {
 4300            log::error!("update_selection dispatched with no pending selection");
 4301            return;
 4302        }
 4303
 4304        self.apply_scroll_delta(scroll_delta, window, cx);
 4305        cx.notify();
 4306    }
 4307
 4308    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4309        self.columnar_selection_state.take();
 4310        if let Some(pending_mode) = self.selections.pending_mode() {
 4311            let selections = self
 4312                .selections
 4313                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4314            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4315                s.select(selections);
 4316                s.clear_pending();
 4317                if s.is_extending() {
 4318                    s.set_is_extending(false);
 4319                } else {
 4320                    s.set_select_mode(pending_mode);
 4321                }
 4322            });
 4323        }
 4324    }
 4325
 4326    fn select_columns(
 4327        &mut self,
 4328        head: DisplayPoint,
 4329        goal_column: u32,
 4330        display_map: &DisplaySnapshot,
 4331        window: &mut Window,
 4332        cx: &mut Context<Self>,
 4333    ) {
 4334        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4335            return;
 4336        };
 4337
 4338        let tail = match columnar_state {
 4339            ColumnarSelectionState::FromMouse {
 4340                selection_tail,
 4341                display_point,
 4342            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4343            ColumnarSelectionState::FromSelection { selection_tail } => {
 4344                selection_tail.to_display_point(display_map)
 4345            }
 4346        };
 4347
 4348        let start_row = cmp::min(tail.row(), head.row());
 4349        let end_row = cmp::max(tail.row(), head.row());
 4350        let start_column = cmp::min(tail.column(), goal_column);
 4351        let end_column = cmp::max(tail.column(), goal_column);
 4352        let reversed = start_column < tail.column();
 4353
 4354        let selection_ranges = (start_row.0..=end_row.0)
 4355            .map(DisplayRow)
 4356            .filter_map(|row| {
 4357                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4358                    || start_column <= display_map.line_len(row))
 4359                    && !display_map.is_block_line(row)
 4360                {
 4361                    let start = display_map
 4362                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4363                        .to_point(display_map);
 4364                    let end = display_map
 4365                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4366                        .to_point(display_map);
 4367                    if reversed {
 4368                        Some(end..start)
 4369                    } else {
 4370                        Some(start..end)
 4371                    }
 4372                } else {
 4373                    None
 4374                }
 4375            })
 4376            .collect::<Vec<_>>();
 4377        if selection_ranges.is_empty() {
 4378            return;
 4379        }
 4380
 4381        let ranges = match columnar_state {
 4382            ColumnarSelectionState::FromMouse { .. } => {
 4383                let mut non_empty_ranges = selection_ranges
 4384                    .iter()
 4385                    .filter(|selection_range| selection_range.start != selection_range.end)
 4386                    .peekable();
 4387                if non_empty_ranges.peek().is_some() {
 4388                    non_empty_ranges.cloned().collect()
 4389                } else {
 4390                    selection_ranges
 4391                }
 4392            }
 4393            _ => selection_ranges,
 4394        };
 4395
 4396        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4397            s.select_ranges(ranges);
 4398        });
 4399        cx.notify();
 4400    }
 4401
 4402    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4403        self.selections
 4404            .all_adjusted(snapshot)
 4405            .iter()
 4406            .any(|selection| !selection.is_empty())
 4407    }
 4408
 4409    pub fn has_pending_nonempty_selection(&self) -> bool {
 4410        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4411            Some(Selection { start, end, .. }) => start != end,
 4412            None => false,
 4413        };
 4414
 4415        pending_nonempty_selection
 4416            || (self.columnar_selection_state.is_some()
 4417                && self.selections.disjoint_anchors().len() > 1)
 4418    }
 4419
 4420    pub fn has_pending_selection(&self) -> bool {
 4421        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4422    }
 4423
 4424    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4425        self.selection_mark_mode = false;
 4426        self.selection_drag_state = SelectionDragState::None;
 4427
 4428        if self.dismiss_menus_and_popups(true, window, cx) {
 4429            cx.notify();
 4430            return;
 4431        }
 4432        if self.clear_expanded_diff_hunks(cx) {
 4433            cx.notify();
 4434            return;
 4435        }
 4436        if self.show_git_blame_gutter {
 4437            self.show_git_blame_gutter = false;
 4438            cx.notify();
 4439            return;
 4440        }
 4441
 4442        if self.mode.is_full()
 4443            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4444        {
 4445            cx.notify();
 4446            return;
 4447        }
 4448
 4449        cx.propagate();
 4450    }
 4451
 4452    pub fn dismiss_menus_and_popups(
 4453        &mut self,
 4454        is_user_requested: bool,
 4455        window: &mut Window,
 4456        cx: &mut Context<Self>,
 4457    ) -> bool {
 4458        let mut dismissed = false;
 4459
 4460        dismissed |= self.take_rename(false, window, cx).is_some();
 4461        dismissed |= self.hide_blame_popover(true, cx);
 4462        dismissed |= hide_hover(self, cx);
 4463        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4464        dismissed |= self.hide_context_menu(window, cx).is_some();
 4465        dismissed |= self.mouse_context_menu.take().is_some();
 4466        dismissed |= is_user_requested
 4467            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4468        dismissed |= self.snippet_stack.pop().is_some();
 4469        if self.diff_review_drag_state.is_some() {
 4470            self.cancel_diff_review_drag(cx);
 4471            dismissed = true;
 4472        }
 4473        if !self.diff_review_overlays.is_empty() {
 4474            self.dismiss_all_diff_review_overlays(cx);
 4475            dismissed = true;
 4476        }
 4477
 4478        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4479            self.dismiss_diagnostics(cx);
 4480            dismissed = true;
 4481        }
 4482
 4483        dismissed
 4484    }
 4485
 4486    fn linked_editing_ranges_for(
 4487        &self,
 4488        selection: Range<text::Anchor>,
 4489        cx: &App,
 4490    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4491        if self.linked_edit_ranges.is_empty() {
 4492            return None;
 4493        }
 4494        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4495            selection.end.buffer_id.and_then(|end_buffer_id| {
 4496                if selection.start.buffer_id != Some(end_buffer_id) {
 4497                    return None;
 4498                }
 4499                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4500                let snapshot = buffer.read(cx).snapshot();
 4501                self.linked_edit_ranges
 4502                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4503                    .map(|ranges| (ranges, snapshot, buffer))
 4504            })?;
 4505        use text::ToOffset as TO;
 4506        // find offset from the start of current range to current cursor position
 4507        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4508
 4509        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4510        let start_difference = start_offset - start_byte_offset;
 4511        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4512        let end_difference = end_offset - start_byte_offset;
 4513        // Current range has associated linked ranges.
 4514        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4515        for range in linked_ranges.iter() {
 4516            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4517            let end_offset = start_offset + end_difference;
 4518            let start_offset = start_offset + start_difference;
 4519            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4520                continue;
 4521            }
 4522            if self.selections.disjoint_anchor_ranges().any(|s| {
 4523                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4524                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4525                {
 4526                    return false;
 4527                }
 4528                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4529                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4530            }) {
 4531                continue;
 4532            }
 4533            let start = buffer_snapshot.anchor_after(start_offset);
 4534            let end = buffer_snapshot.anchor_after(end_offset);
 4535            linked_edits
 4536                .entry(buffer.clone())
 4537                .or_default()
 4538                .push(start..end);
 4539        }
 4540        Some(linked_edits)
 4541    }
 4542
 4543    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4544        let text: Arc<str> = text.into();
 4545
 4546        if self.read_only(cx) {
 4547            return;
 4548        }
 4549
 4550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4551
 4552        self.unfold_buffers_with_selections(cx);
 4553
 4554        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4555        let mut bracket_inserted = false;
 4556        let mut edits = Vec::new();
 4557        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4558        let mut new_selections = Vec::with_capacity(selections.len());
 4559        let mut new_autoclose_regions = Vec::new();
 4560        let snapshot = self.buffer.read(cx).read(cx);
 4561        let mut clear_linked_edit_ranges = false;
 4562        let mut all_selections_read_only = true;
 4563        let mut has_adjacent_edits = false;
 4564        let mut in_adjacent_group = false;
 4565
 4566        let mut regions = self
 4567            .selections_with_autoclose_regions(selections, &snapshot)
 4568            .peekable();
 4569
 4570        while let Some((selection, autoclose_region)) = regions.next() {
 4571            if snapshot
 4572                .point_to_buffer_point(selection.head())
 4573                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4574            {
 4575                continue;
 4576            }
 4577            if snapshot
 4578                .point_to_buffer_point(selection.tail())
 4579                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4580            {
 4581                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4582                continue;
 4583            }
 4584            all_selections_read_only = false;
 4585
 4586            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4587                // Determine if the inserted text matches the opening or closing
 4588                // bracket of any of this language's bracket pairs.
 4589                let mut bracket_pair = None;
 4590                let mut is_bracket_pair_start = false;
 4591                let mut is_bracket_pair_end = false;
 4592                if !text.is_empty() {
 4593                    let mut bracket_pair_matching_end = None;
 4594                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4595                    //  and they are removing the character that triggered IME popup.
 4596                    for (pair, enabled) in scope.brackets() {
 4597                        if !pair.close && !pair.surround {
 4598                            continue;
 4599                        }
 4600
 4601                        if enabled && pair.start.ends_with(text.as_ref()) {
 4602                            let prefix_len = pair.start.len() - text.len();
 4603                            let preceding_text_matches_prefix = prefix_len == 0
 4604                                || (selection.start.column >= (prefix_len as u32)
 4605                                    && snapshot.contains_str_at(
 4606                                        Point::new(
 4607                                            selection.start.row,
 4608                                            selection.start.column - (prefix_len as u32),
 4609                                        ),
 4610                                        &pair.start[..prefix_len],
 4611                                    ));
 4612                            if preceding_text_matches_prefix {
 4613                                bracket_pair = Some(pair.clone());
 4614                                is_bracket_pair_start = true;
 4615                                break;
 4616                            }
 4617                        }
 4618                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4619                        {
 4620                            // take first bracket pair matching end, but don't break in case a later bracket
 4621                            // pair matches start
 4622                            bracket_pair_matching_end = Some(pair.clone());
 4623                        }
 4624                    }
 4625                    if let Some(end) = bracket_pair_matching_end
 4626                        && bracket_pair.is_none()
 4627                    {
 4628                        bracket_pair = Some(end);
 4629                        is_bracket_pair_end = true;
 4630                    }
 4631                }
 4632
 4633                if let Some(bracket_pair) = bracket_pair {
 4634                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4635                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4636                    let auto_surround =
 4637                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4638                    if selection.is_empty() {
 4639                        if is_bracket_pair_start {
 4640                            // If the inserted text is a suffix of an opening bracket and the
 4641                            // selection is preceded by the rest of the opening bracket, then
 4642                            // insert the closing bracket.
 4643                            let following_text_allows_autoclose = snapshot
 4644                                .chars_at(selection.start)
 4645                                .next()
 4646                                .is_none_or(|c| scope.should_autoclose_before(c));
 4647
 4648                            let preceding_text_allows_autoclose = selection.start.column == 0
 4649                                || snapshot
 4650                                    .reversed_chars_at(selection.start)
 4651                                    .next()
 4652                                    .is_none_or(|c| {
 4653                                        bracket_pair.start != bracket_pair.end
 4654                                            || !snapshot
 4655                                                .char_classifier_at(selection.start)
 4656                                                .is_word(c)
 4657                                    });
 4658
 4659                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4660                                && bracket_pair.start.len() == 1
 4661                            {
 4662                                let target = bracket_pair.start.chars().next().unwrap();
 4663                                let mut byte_offset = 0u32;
 4664                                let current_line_count = snapshot
 4665                                    .reversed_chars_at(selection.start)
 4666                                    .take_while(|&c| c != '\n')
 4667                                    .filter(|c| {
 4668                                        byte_offset += c.len_utf8() as u32;
 4669                                        if *c != target {
 4670                                            return false;
 4671                                        }
 4672
 4673                                        let point = Point::new(
 4674                                            selection.start.row,
 4675                                            selection.start.column.saturating_sub(byte_offset),
 4676                                        );
 4677
 4678                                        let is_enabled = snapshot
 4679                                            .language_scope_at(point)
 4680                                            .and_then(|scope| {
 4681                                                scope
 4682                                                    .brackets()
 4683                                                    .find(|(pair, _)| {
 4684                                                        pair.start == bracket_pair.start
 4685                                                    })
 4686                                                    .map(|(_, enabled)| enabled)
 4687                                            })
 4688                                            .unwrap_or(true);
 4689
 4690                                        let is_delimiter = snapshot
 4691                                            .language_scope_at(Point::new(
 4692                                                point.row,
 4693                                                point.column + 1,
 4694                                            ))
 4695                                            .and_then(|scope| {
 4696                                                scope
 4697                                                    .brackets()
 4698                                                    .find(|(pair, _)| {
 4699                                                        pair.start == bracket_pair.start
 4700                                                    })
 4701                                                    .map(|(_, enabled)| !enabled)
 4702                                            })
 4703                                            .unwrap_or(false);
 4704
 4705                                        is_enabled && !is_delimiter
 4706                                    })
 4707                                    .count();
 4708                                current_line_count % 2 == 1
 4709                            } else {
 4710                                false
 4711                            };
 4712
 4713                            if autoclose
 4714                                && bracket_pair.close
 4715                                && following_text_allows_autoclose
 4716                                && preceding_text_allows_autoclose
 4717                                && !is_closing_quote
 4718                            {
 4719                                let anchor = snapshot.anchor_before(selection.end);
 4720                                new_selections.push((selection.map(|_| anchor), text.len()));
 4721                                new_autoclose_regions.push((
 4722                                    anchor,
 4723                                    text.len(),
 4724                                    selection.id,
 4725                                    bracket_pair.clone(),
 4726                                ));
 4727                                edits.push((
 4728                                    selection.range(),
 4729                                    format!("{}{}", text, bracket_pair.end).into(),
 4730                                ));
 4731                                bracket_inserted = true;
 4732                                continue;
 4733                            }
 4734                        }
 4735
 4736                        if let Some(region) = autoclose_region {
 4737                            // If the selection is followed by an auto-inserted closing bracket,
 4738                            // then don't insert that closing bracket again; just move the selection
 4739                            // past the closing bracket.
 4740                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4741                                && text.as_ref() == region.pair.end.as_str()
 4742                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4743                            if should_skip {
 4744                                let anchor = snapshot.anchor_after(selection.end);
 4745                                new_selections
 4746                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4747                                continue;
 4748                            }
 4749                        }
 4750
 4751                        let always_treat_brackets_as_autoclosed = snapshot
 4752                            .language_settings_at(selection.start, cx)
 4753                            .always_treat_brackets_as_autoclosed;
 4754                        if always_treat_brackets_as_autoclosed
 4755                            && is_bracket_pair_end
 4756                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4757                        {
 4758                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4759                            // and the inserted text is a closing bracket and the selection is followed
 4760                            // by the closing bracket then move the selection past the closing bracket.
 4761                            let anchor = snapshot.anchor_after(selection.end);
 4762                            new_selections.push((selection.map(|_| anchor), text.len()));
 4763                            continue;
 4764                        }
 4765                    }
 4766                    // If an opening bracket is 1 character long and is typed while
 4767                    // text is selected, then surround that text with the bracket pair.
 4768                    else if auto_surround
 4769                        && bracket_pair.surround
 4770                        && is_bracket_pair_start
 4771                        && bracket_pair.start.chars().count() == 1
 4772                    {
 4773                        edits.push((selection.start..selection.start, text.clone()));
 4774                        edits.push((
 4775                            selection.end..selection.end,
 4776                            bracket_pair.end.as_str().into(),
 4777                        ));
 4778                        bracket_inserted = true;
 4779                        new_selections.push((
 4780                            Selection {
 4781                                id: selection.id,
 4782                                start: snapshot.anchor_after(selection.start),
 4783                                end: snapshot.anchor_before(selection.end),
 4784                                reversed: selection.reversed,
 4785                                goal: selection.goal,
 4786                            },
 4787                            0,
 4788                        ));
 4789                        continue;
 4790                    }
 4791                }
 4792            }
 4793
 4794            if self.auto_replace_emoji_shortcode
 4795                && selection.is_empty()
 4796                && text.as_ref().ends_with(':')
 4797                && let Some(possible_emoji_short_code) =
 4798                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4799                && !possible_emoji_short_code.is_empty()
 4800                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4801            {
 4802                let emoji_shortcode_start = Point::new(
 4803                    selection.start.row,
 4804                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4805                );
 4806
 4807                // Remove shortcode from buffer
 4808                edits.push((
 4809                    emoji_shortcode_start..selection.start,
 4810                    "".to_string().into(),
 4811                ));
 4812                new_selections.push((
 4813                    Selection {
 4814                        id: selection.id,
 4815                        start: snapshot.anchor_after(emoji_shortcode_start),
 4816                        end: snapshot.anchor_before(selection.start),
 4817                        reversed: selection.reversed,
 4818                        goal: selection.goal,
 4819                    },
 4820                    0,
 4821                ));
 4822
 4823                // Insert emoji
 4824                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4825                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4826                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4827
 4828                continue;
 4829            }
 4830
 4831            let next_is_adjacent = regions
 4832                .peek()
 4833                .is_some_and(|(next, _)| selection.end == next.start);
 4834
 4835            // If not handling any auto-close operation, then just replace the selected
 4836            // text with the given input and move the selection to the end of the
 4837            // newly inserted text.
 4838            let anchor = if in_adjacent_group || next_is_adjacent {
 4839                // After edits the right bias would shift those anchor to the next visible fragment
 4840                // but we want to resolve to the previous one
 4841                snapshot.anchor_before(selection.end)
 4842            } else {
 4843                snapshot.anchor_after(selection.end)
 4844            };
 4845
 4846            if !self.linked_edit_ranges.is_empty() {
 4847                let start_anchor = snapshot.anchor_before(selection.start);
 4848
 4849                let is_word_char = text.chars().next().is_none_or(|char| {
 4850                    let classifier = snapshot
 4851                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4852                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4853                    classifier.is_word(char)
 4854                });
 4855
 4856                if is_word_char {
 4857                    if let Some(ranges) = self
 4858                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4859                    {
 4860                        for (buffer, edits) in ranges {
 4861                            linked_edits
 4862                                .entry(buffer.clone())
 4863                                .or_default()
 4864                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4865                        }
 4866                    }
 4867                } else {
 4868                    clear_linked_edit_ranges = true;
 4869                }
 4870            }
 4871
 4872            new_selections.push((selection.map(|_| anchor), 0));
 4873            edits.push((selection.start..selection.end, text.clone()));
 4874
 4875            has_adjacent_edits |= next_is_adjacent;
 4876            in_adjacent_group = next_is_adjacent;
 4877        }
 4878
 4879        if all_selections_read_only {
 4880            return;
 4881        }
 4882
 4883        drop(regions);
 4884        drop(snapshot);
 4885
 4886        self.transact(window, cx, |this, window, cx| {
 4887            if clear_linked_edit_ranges {
 4888                this.linked_edit_ranges.clear();
 4889            }
 4890            let initial_buffer_versions =
 4891                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4892
 4893            this.buffer.update(cx, |buffer, cx| {
 4894                if has_adjacent_edits {
 4895                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4896                } else {
 4897                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4898                }
 4899            });
 4900            for (buffer, edits) in linked_edits {
 4901                buffer.update(cx, |buffer, cx| {
 4902                    let snapshot = buffer.snapshot();
 4903                    let edits = edits
 4904                        .into_iter()
 4905                        .map(|(range, text)| {
 4906                            use text::ToPoint as TP;
 4907                            let end_point = TP::to_point(&range.end, &snapshot);
 4908                            let start_point = TP::to_point(&range.start, &snapshot);
 4909                            (start_point..end_point, text)
 4910                        })
 4911                        .sorted_by_key(|(range, _)| range.start);
 4912                    buffer.edit(edits, None, cx);
 4913                })
 4914            }
 4915            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4916            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4917            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4918            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4919                new_anchor_selections,
 4920                &map,
 4921            )
 4922            .zip(new_selection_deltas)
 4923            .map(|(selection, delta)| Selection {
 4924                id: selection.id,
 4925                start: selection.start + delta,
 4926                end: selection.end + delta,
 4927                reversed: selection.reversed,
 4928                goal: SelectionGoal::None,
 4929            })
 4930            .collect::<Vec<_>>();
 4931
 4932            let mut i = 0;
 4933            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4934                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4935                let start = map.buffer_snapshot().anchor_before(position);
 4936                let end = map.buffer_snapshot().anchor_after(position);
 4937                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4938                    match existing_state
 4939                        .range
 4940                        .start
 4941                        .cmp(&start, map.buffer_snapshot())
 4942                    {
 4943                        Ordering::Less => i += 1,
 4944                        Ordering::Greater => break,
 4945                        Ordering::Equal => {
 4946                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4947                                Ordering::Less => i += 1,
 4948                                Ordering::Equal => break,
 4949                                Ordering::Greater => break,
 4950                            }
 4951                        }
 4952                    }
 4953                }
 4954                this.autoclose_regions.insert(
 4955                    i,
 4956                    AutocloseRegion {
 4957                        selection_id,
 4958                        range: start..end,
 4959                        pair,
 4960                    },
 4961                );
 4962            }
 4963
 4964            let had_active_edit_prediction = this.has_active_edit_prediction();
 4965            this.change_selections(
 4966                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4967                window,
 4968                cx,
 4969                |s| s.select(new_selections),
 4970            );
 4971
 4972            if !bracket_inserted
 4973                && let Some(on_type_format_task) =
 4974                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4975            {
 4976                on_type_format_task.detach_and_log_err(cx);
 4977            }
 4978
 4979            let editor_settings = EditorSettings::get_global(cx);
 4980            if bracket_inserted
 4981                && (editor_settings.auto_signature_help
 4982                    || editor_settings.show_signature_help_after_edits)
 4983            {
 4984                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4985            }
 4986
 4987            let trigger_in_words =
 4988                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4989            if this.hard_wrap.is_some() {
 4990                let latest: Range<Point> = this.selections.newest(&map).range();
 4991                if latest.is_empty()
 4992                    && this
 4993                        .buffer()
 4994                        .read(cx)
 4995                        .snapshot(cx)
 4996                        .line_len(MultiBufferRow(latest.start.row))
 4997                        == latest.start.column
 4998                {
 4999                    this.rewrap_impl(
 5000                        RewrapOptions {
 5001                            override_language_settings: true,
 5002                            preserve_existing_whitespace: true,
 5003                        },
 5004                        cx,
 5005                    )
 5006                }
 5007            }
 5008            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 5009            refresh_linked_ranges(this, window, cx);
 5010            this.refresh_edit_prediction(true, false, window, cx);
 5011            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5012        });
 5013    }
 5014
 5015    fn find_possible_emoji_shortcode_at_position(
 5016        snapshot: &MultiBufferSnapshot,
 5017        position: Point,
 5018    ) -> Option<String> {
 5019        let mut chars = Vec::new();
 5020        let mut found_colon = false;
 5021        for char in snapshot.reversed_chars_at(position).take(100) {
 5022            // Found a possible emoji shortcode in the middle of the buffer
 5023            if found_colon {
 5024                if char.is_whitespace() {
 5025                    chars.reverse();
 5026                    return Some(chars.iter().collect());
 5027                }
 5028                // If the previous character is not a whitespace, we are in the middle of a word
 5029                // and we only want to complete the shortcode if the word is made up of other emojis
 5030                let mut containing_word = String::new();
 5031                for ch in snapshot
 5032                    .reversed_chars_at(position)
 5033                    .skip(chars.len() + 1)
 5034                    .take(100)
 5035                {
 5036                    if ch.is_whitespace() {
 5037                        break;
 5038                    }
 5039                    containing_word.push(ch);
 5040                }
 5041                let containing_word = containing_word.chars().rev().collect::<String>();
 5042                if util::word_consists_of_emojis(containing_word.as_str()) {
 5043                    chars.reverse();
 5044                    return Some(chars.iter().collect());
 5045                }
 5046            }
 5047
 5048            if char.is_whitespace() || !char.is_ascii() {
 5049                return None;
 5050            }
 5051            if char == ':' {
 5052                found_colon = true;
 5053            } else {
 5054                chars.push(char);
 5055            }
 5056        }
 5057        // Found a possible emoji shortcode at the beginning of the buffer
 5058        chars.reverse();
 5059        Some(chars.iter().collect())
 5060    }
 5061
 5062    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5064        self.transact(window, cx, |this, window, cx| {
 5065            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5066                let selections = this
 5067                    .selections
 5068                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5069                let multi_buffer = this.buffer.read(cx);
 5070                let buffer = multi_buffer.snapshot(cx);
 5071                selections
 5072                    .iter()
 5073                    .map(|selection| {
 5074                        let start_point = selection.start.to_point(&buffer);
 5075                        let mut existing_indent =
 5076                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5077                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5078                        let start = selection.start;
 5079                        let end = selection.end;
 5080                        let selection_is_empty = start == end;
 5081                        let language_scope = buffer.language_scope_at(start);
 5082                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5083                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5084                                &buffer,
 5085                                start..end,
 5086                                language,
 5087                            )
 5088                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5089                                    &buffer,
 5090                                    start..end,
 5091                                );
 5092
 5093                            let mut newline_config = NewlineConfig::Newline {
 5094                                additional_indent: IndentSize::spaces(0),
 5095                                extra_line_additional_indent: if needs_extra_newline {
 5096                                    Some(IndentSize::spaces(0))
 5097                                } else {
 5098                                    None
 5099                                },
 5100                                prevent_auto_indent: false,
 5101                            };
 5102
 5103                            let comment_delimiter = maybe!({
 5104                                if !selection_is_empty {
 5105                                    return None;
 5106                                }
 5107
 5108                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5109                                    return None;
 5110                                }
 5111
 5112                                return comment_delimiter_for_newline(
 5113                                    &start_point,
 5114                                    &buffer,
 5115                                    language,
 5116                                );
 5117                            });
 5118
 5119                            let doc_delimiter = maybe!({
 5120                                if !selection_is_empty {
 5121                                    return None;
 5122                                }
 5123
 5124                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5125                                    return None;
 5126                                }
 5127
 5128                                return documentation_delimiter_for_newline(
 5129                                    &start_point,
 5130                                    &buffer,
 5131                                    language,
 5132                                    &mut newline_config,
 5133                                );
 5134                            });
 5135
 5136                            let list_delimiter = maybe!({
 5137                                if !selection_is_empty {
 5138                                    return None;
 5139                                }
 5140
 5141                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5142                                    return None;
 5143                                }
 5144
 5145                                return list_delimiter_for_newline(
 5146                                    &start_point,
 5147                                    &buffer,
 5148                                    language,
 5149                                    &mut newline_config,
 5150                                );
 5151                            });
 5152
 5153                            (
 5154                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5155                                newline_config,
 5156                            )
 5157                        } else {
 5158                            (
 5159                                None,
 5160                                NewlineConfig::Newline {
 5161                                    additional_indent: IndentSize::spaces(0),
 5162                                    extra_line_additional_indent: None,
 5163                                    prevent_auto_indent: false,
 5164                                },
 5165                            )
 5166                        };
 5167
 5168                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5169                            NewlineConfig::ClearCurrentLine => {
 5170                                let row_start =
 5171                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5172                                (row_start, String::new(), false)
 5173                            }
 5174                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5175                                let row_start =
 5176                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5177                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5178                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5179                                let reduced_indent =
 5180                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5181                                let mut new_text = String::new();
 5182                                new_text.extend(reduced_indent.chars());
 5183                                new_text.push_str(continuation);
 5184                                (row_start, new_text, true)
 5185                            }
 5186                            NewlineConfig::Newline {
 5187                                additional_indent,
 5188                                extra_line_additional_indent,
 5189                                prevent_auto_indent,
 5190                            } => {
 5191                                let capacity_for_delimiter =
 5192                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5193                                let extra_line_len = extra_line_additional_indent
 5194                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 5195                                    .unwrap_or(0);
 5196                                let mut new_text = String::with_capacity(
 5197                                    1 + capacity_for_delimiter
 5198                                        + existing_indent.len as usize
 5199                                        + additional_indent.len as usize
 5200                                        + extra_line_len,
 5201                                );
 5202                                new_text.push('\n');
 5203                                new_text.extend(existing_indent.chars());
 5204                                new_text.extend(additional_indent.chars());
 5205                                if let Some(delimiter) = &delimiter {
 5206                                    new_text.push_str(delimiter);
 5207                                }
 5208                                if let Some(extra_indent) = extra_line_additional_indent {
 5209                                    new_text.push('\n');
 5210                                    new_text.extend(existing_indent.chars());
 5211                                    new_text.extend(extra_indent.chars());
 5212                                }
 5213                                (start, new_text, *prevent_auto_indent)
 5214                            }
 5215                        };
 5216
 5217                        let anchor = buffer.anchor_after(end);
 5218                        let new_selection = selection.map(|_| anchor);
 5219                        (
 5220                            ((edit_start..end, new_text), prevent_auto_indent),
 5221                            (newline_config.has_extra_line(), new_selection),
 5222                        )
 5223                    })
 5224                    .unzip()
 5225            };
 5226
 5227            let mut auto_indent_edits = Vec::new();
 5228            let mut edits = Vec::new();
 5229            for (edit, prevent_auto_indent) in edits_with_flags {
 5230                if prevent_auto_indent {
 5231                    edits.push(edit);
 5232                } else {
 5233                    auto_indent_edits.push(edit);
 5234                }
 5235            }
 5236            if !edits.is_empty() {
 5237                this.edit(edits, cx);
 5238            }
 5239            if !auto_indent_edits.is_empty() {
 5240                this.edit_with_autoindent(auto_indent_edits, cx);
 5241            }
 5242
 5243            let buffer = this.buffer.read(cx).snapshot(cx);
 5244            let new_selections = selection_info
 5245                .into_iter()
 5246                .map(|(extra_newline_inserted, new_selection)| {
 5247                    let mut cursor = new_selection.end.to_point(&buffer);
 5248                    if extra_newline_inserted {
 5249                        cursor.row -= 1;
 5250                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5251                    }
 5252                    new_selection.map(|_| cursor)
 5253                })
 5254                .collect();
 5255
 5256            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5257            this.refresh_edit_prediction(true, false, window, cx);
 5258            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5259                task.detach_and_log_err(cx);
 5260            }
 5261        });
 5262    }
 5263
 5264    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5265        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5266
 5267        let buffer = self.buffer.read(cx);
 5268        let snapshot = buffer.snapshot(cx);
 5269
 5270        let mut edits = Vec::new();
 5271        let mut rows = Vec::new();
 5272
 5273        for (rows_inserted, selection) in self
 5274            .selections
 5275            .all_adjusted(&self.display_snapshot(cx))
 5276            .into_iter()
 5277            .enumerate()
 5278        {
 5279            let cursor = selection.head();
 5280            let row = cursor.row;
 5281
 5282            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5283
 5284            let newline = "\n".to_string();
 5285            edits.push((start_of_line..start_of_line, newline));
 5286
 5287            rows.push(row + rows_inserted as u32);
 5288        }
 5289
 5290        self.transact(window, cx, |editor, window, cx| {
 5291            editor.edit(edits, cx);
 5292
 5293            editor.change_selections(Default::default(), window, cx, |s| {
 5294                let mut index = 0;
 5295                s.move_cursors_with(|map, _, _| {
 5296                    let row = rows[index];
 5297                    index += 1;
 5298
 5299                    let point = Point::new(row, 0);
 5300                    let boundary = map.next_line_boundary(point).1;
 5301                    let clipped = map.clip_point(boundary, Bias::Left);
 5302
 5303                    (clipped, SelectionGoal::None)
 5304                });
 5305            });
 5306
 5307            let mut indent_edits = Vec::new();
 5308            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5309            for row in rows {
 5310                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5311                for (row, indent) in indents {
 5312                    if indent.len == 0 {
 5313                        continue;
 5314                    }
 5315
 5316                    let text = match indent.kind {
 5317                        IndentKind::Space => " ".repeat(indent.len as usize),
 5318                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5319                    };
 5320                    let point = Point::new(row.0, 0);
 5321                    indent_edits.push((point..point, text));
 5322                }
 5323            }
 5324            editor.edit(indent_edits, cx);
 5325            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5326                format.detach_and_log_err(cx);
 5327            }
 5328        });
 5329    }
 5330
 5331    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5332        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5333
 5334        let buffer = self.buffer.read(cx);
 5335        let snapshot = buffer.snapshot(cx);
 5336
 5337        let mut edits = Vec::new();
 5338        let mut rows = Vec::new();
 5339        let mut rows_inserted = 0;
 5340
 5341        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5342            let cursor = selection.head();
 5343            let row = cursor.row;
 5344
 5345            let point = Point::new(row + 1, 0);
 5346            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5347
 5348            let newline = "\n".to_string();
 5349            edits.push((start_of_line..start_of_line, newline));
 5350
 5351            rows_inserted += 1;
 5352            rows.push(row + rows_inserted);
 5353        }
 5354
 5355        self.transact(window, cx, |editor, window, cx| {
 5356            editor.edit(edits, cx);
 5357
 5358            editor.change_selections(Default::default(), window, cx, |s| {
 5359                let mut index = 0;
 5360                s.move_cursors_with(|map, _, _| {
 5361                    let row = rows[index];
 5362                    index += 1;
 5363
 5364                    let point = Point::new(row, 0);
 5365                    let boundary = map.next_line_boundary(point).1;
 5366                    let clipped = map.clip_point(boundary, Bias::Left);
 5367
 5368                    (clipped, SelectionGoal::None)
 5369                });
 5370            });
 5371
 5372            let mut indent_edits = Vec::new();
 5373            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5374            for row in rows {
 5375                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5376                for (row, indent) in indents {
 5377                    if indent.len == 0 {
 5378                        continue;
 5379                    }
 5380
 5381                    let text = match indent.kind {
 5382                        IndentKind::Space => " ".repeat(indent.len as usize),
 5383                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5384                    };
 5385                    let point = Point::new(row.0, 0);
 5386                    indent_edits.push((point..point, text));
 5387                }
 5388            }
 5389            editor.edit(indent_edits, cx);
 5390            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5391                format.detach_and_log_err(cx);
 5392            }
 5393        });
 5394    }
 5395
 5396    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5397        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5398            original_indent_columns: Vec::new(),
 5399        });
 5400        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5401    }
 5402
 5403    fn insert_with_autoindent_mode(
 5404        &mut self,
 5405        text: &str,
 5406        autoindent_mode: Option<AutoindentMode>,
 5407        window: &mut Window,
 5408        cx: &mut Context<Self>,
 5409    ) {
 5410        if self.read_only(cx) {
 5411            return;
 5412        }
 5413
 5414        let text: Arc<str> = text.into();
 5415        self.transact(window, cx, |this, window, cx| {
 5416            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5417            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5418                let anchors = {
 5419                    let snapshot = buffer.read(cx);
 5420                    old_selections
 5421                        .iter()
 5422                        .map(|s| {
 5423                            let anchor = snapshot.anchor_after(s.head());
 5424                            s.map(|_| anchor)
 5425                        })
 5426                        .collect::<Vec<_>>()
 5427                };
 5428                buffer.edit(
 5429                    old_selections
 5430                        .iter()
 5431                        .map(|s| (s.start..s.end, text.clone())),
 5432                    autoindent_mode,
 5433                    cx,
 5434                );
 5435                anchors
 5436            });
 5437
 5438            this.change_selections(Default::default(), window, cx, |s| {
 5439                s.select_anchors(selection_anchors);
 5440            });
 5441
 5442            cx.notify();
 5443        });
 5444    }
 5445
 5446    fn trigger_completion_on_input(
 5447        &mut self,
 5448        text: &str,
 5449        trigger_in_words: bool,
 5450        window: &mut Window,
 5451        cx: &mut Context<Self>,
 5452    ) {
 5453        let completions_source = self
 5454            .context_menu
 5455            .borrow()
 5456            .as_ref()
 5457            .and_then(|menu| match menu {
 5458                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5459                CodeContextMenu::CodeActions(_) => None,
 5460            });
 5461
 5462        match completions_source {
 5463            Some(CompletionsMenuSource::Words { .. }) => {
 5464                self.open_or_update_completions_menu(
 5465                    Some(CompletionsMenuSource::Words {
 5466                        ignore_threshold: false,
 5467                    }),
 5468                    None,
 5469                    trigger_in_words,
 5470                    window,
 5471                    cx,
 5472                );
 5473            }
 5474            _ => self.open_or_update_completions_menu(
 5475                None,
 5476                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5477                true,
 5478                window,
 5479                cx,
 5480            ),
 5481        }
 5482    }
 5483
 5484    /// If any empty selections is touching the start of its innermost containing autoclose
 5485    /// region, expand it to select the brackets.
 5486    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5487        let selections = self
 5488            .selections
 5489            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5490        let buffer = self.buffer.read(cx).read(cx);
 5491        let new_selections = self
 5492            .selections_with_autoclose_regions(selections, &buffer)
 5493            .map(|(mut selection, region)| {
 5494                if !selection.is_empty() {
 5495                    return selection;
 5496                }
 5497
 5498                if let Some(region) = region {
 5499                    let mut range = region.range.to_offset(&buffer);
 5500                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5501                        range.start -= region.pair.start.len();
 5502                        if buffer.contains_str_at(range.start, &region.pair.start)
 5503                            && buffer.contains_str_at(range.end, &region.pair.end)
 5504                        {
 5505                            range.end += region.pair.end.len();
 5506                            selection.start = range.start;
 5507                            selection.end = range.end;
 5508
 5509                            return selection;
 5510                        }
 5511                    }
 5512                }
 5513
 5514                let always_treat_brackets_as_autoclosed = buffer
 5515                    .language_settings_at(selection.start, cx)
 5516                    .always_treat_brackets_as_autoclosed;
 5517
 5518                if !always_treat_brackets_as_autoclosed {
 5519                    return selection;
 5520                }
 5521
 5522                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5523                    for (pair, enabled) in scope.brackets() {
 5524                        if !enabled || !pair.close {
 5525                            continue;
 5526                        }
 5527
 5528                        if buffer.contains_str_at(selection.start, &pair.end) {
 5529                            let pair_start_len = pair.start.len();
 5530                            if buffer.contains_str_at(
 5531                                selection.start.saturating_sub_usize(pair_start_len),
 5532                                &pair.start,
 5533                            ) {
 5534                                selection.start -= pair_start_len;
 5535                                selection.end += pair.end.len();
 5536
 5537                                return selection;
 5538                            }
 5539                        }
 5540                    }
 5541                }
 5542
 5543                selection
 5544            })
 5545            .collect();
 5546
 5547        drop(buffer);
 5548        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5549            selections.select(new_selections)
 5550        });
 5551    }
 5552
 5553    /// Iterate the given selections, and for each one, find the smallest surrounding
 5554    /// autoclose region. This uses the ordering of the selections and the autoclose
 5555    /// regions to avoid repeated comparisons.
 5556    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5557        &'a self,
 5558        selections: impl IntoIterator<Item = Selection<D>>,
 5559        buffer: &'a MultiBufferSnapshot,
 5560    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5561        let mut i = 0;
 5562        let mut regions = self.autoclose_regions.as_slice();
 5563        selections.into_iter().map(move |selection| {
 5564            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5565
 5566            let mut enclosing = None;
 5567            while let Some(pair_state) = regions.get(i) {
 5568                if pair_state.range.end.to_offset(buffer) < range.start {
 5569                    regions = &regions[i + 1..];
 5570                    i = 0;
 5571                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5572                    break;
 5573                } else {
 5574                    if pair_state.selection_id == selection.id {
 5575                        enclosing = Some(pair_state);
 5576                    }
 5577                    i += 1;
 5578                }
 5579            }
 5580
 5581            (selection, enclosing)
 5582        })
 5583    }
 5584
 5585    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5586    fn invalidate_autoclose_regions(
 5587        &mut self,
 5588        mut selections: &[Selection<Anchor>],
 5589        buffer: &MultiBufferSnapshot,
 5590    ) {
 5591        self.autoclose_regions.retain(|state| {
 5592            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5593                return false;
 5594            }
 5595
 5596            let mut i = 0;
 5597            while let Some(selection) = selections.get(i) {
 5598                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5599                    selections = &selections[1..];
 5600                    continue;
 5601                }
 5602                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5603                    break;
 5604                }
 5605                if selection.id == state.selection_id {
 5606                    return true;
 5607                } else {
 5608                    i += 1;
 5609                }
 5610            }
 5611            false
 5612        });
 5613    }
 5614
 5615    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5616        let offset = position.to_offset(buffer);
 5617        let (word_range, kind) =
 5618            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5619        if offset > word_range.start && kind == Some(CharKind::Word) {
 5620            Some(
 5621                buffer
 5622                    .text_for_range(word_range.start..offset)
 5623                    .collect::<String>(),
 5624            )
 5625        } else {
 5626            None
 5627        }
 5628    }
 5629
 5630    pub fn visible_excerpts(
 5631        &self,
 5632        lsp_related_only: bool,
 5633        cx: &mut Context<Editor>,
 5634    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5635        let project = self.project().cloned();
 5636        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5637        let multi_buffer = self.buffer().read(cx);
 5638        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5639        let multi_buffer_visible_start = self
 5640            .scroll_manager
 5641            .native_anchor(&display_snapshot, cx)
 5642            .anchor
 5643            .to_point(&multi_buffer_snapshot);
 5644        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5645            multi_buffer_visible_start
 5646                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5647            Bias::Left,
 5648        );
 5649        multi_buffer_snapshot
 5650            .range_to_buffer_ranges(multi_buffer_visible_start..=multi_buffer_visible_end)
 5651            .into_iter()
 5652            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5653            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5654                if !lsp_related_only {
 5655                    return Some((
 5656                        excerpt_id,
 5657                        (
 5658                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5659                            buffer.version().clone(),
 5660                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5661                        ),
 5662                    ));
 5663                }
 5664
 5665                let project = project.as_ref()?.read(cx);
 5666                let buffer_file = project::File::from_dyn(buffer.file())?;
 5667                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5668                let worktree_entry = buffer_worktree
 5669                    .read(cx)
 5670                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5671                if worktree_entry.is_ignored {
 5672                    None
 5673                } else {
 5674                    Some((
 5675                        excerpt_id,
 5676                        (
 5677                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5678                            buffer.version().clone(),
 5679                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5680                        ),
 5681                    ))
 5682                }
 5683            })
 5684            .collect()
 5685    }
 5686
 5687    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 5688        TextLayoutDetails {
 5689            text_system: window.text_system().clone(),
 5690            editor_style: self.style.clone().unwrap(),
 5691            rem_size: window.rem_size(),
 5692            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 5693            visible_rows: self.visible_line_count(),
 5694            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5695        }
 5696    }
 5697
 5698    fn trigger_on_type_formatting(
 5699        &self,
 5700        input: String,
 5701        window: &mut Window,
 5702        cx: &mut Context<Self>,
 5703    ) -> Option<Task<Result<()>>> {
 5704        if input.chars().count() != 1 {
 5705            return None;
 5706        }
 5707
 5708        let project = self.project()?;
 5709        let position = self.selections.newest_anchor().head();
 5710        let (buffer, buffer_position) = self
 5711            .buffer
 5712            .read(cx)
 5713            .text_anchor_for_position(position, cx)?;
 5714
 5715        let settings = language_settings::language_settings(
 5716            buffer
 5717                .read(cx)
 5718                .language_at(buffer_position)
 5719                .map(|l| l.name()),
 5720            buffer.read(cx).file(),
 5721            cx,
 5722        );
 5723        if !settings.use_on_type_format {
 5724            return None;
 5725        }
 5726
 5727        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5728        // hence we do LSP request & edit on host side only — add formats to host's history.
 5729        let push_to_lsp_host_history = true;
 5730        // If this is not the host, append its history with new edits.
 5731        let push_to_client_history = project.read(cx).is_via_collab();
 5732
 5733        let on_type_formatting = project.update(cx, |project, cx| {
 5734            project.on_type_format(
 5735                buffer.clone(),
 5736                buffer_position,
 5737                input,
 5738                push_to_lsp_host_history,
 5739                cx,
 5740            )
 5741        });
 5742        Some(cx.spawn_in(window, async move |editor, cx| {
 5743            if let Some(transaction) = on_type_formatting.await? {
 5744                if push_to_client_history {
 5745                    buffer.update(cx, |buffer, _| {
 5746                        buffer.push_transaction(transaction, Instant::now());
 5747                        buffer.finalize_last_transaction();
 5748                    });
 5749                }
 5750                editor.update(cx, |editor, cx| {
 5751                    editor.refresh_document_highlights(cx);
 5752                })?;
 5753            }
 5754            Ok(())
 5755        }))
 5756    }
 5757
 5758    pub fn show_word_completions(
 5759        &mut self,
 5760        _: &ShowWordCompletions,
 5761        window: &mut Window,
 5762        cx: &mut Context<Self>,
 5763    ) {
 5764        self.open_or_update_completions_menu(
 5765            Some(CompletionsMenuSource::Words {
 5766                ignore_threshold: true,
 5767            }),
 5768            None,
 5769            false,
 5770            window,
 5771            cx,
 5772        );
 5773    }
 5774
 5775    pub fn show_completions(
 5776        &mut self,
 5777        _: &ShowCompletions,
 5778        window: &mut Window,
 5779        cx: &mut Context<Self>,
 5780    ) {
 5781        self.open_or_update_completions_menu(None, None, false, window, cx);
 5782    }
 5783
 5784    fn open_or_update_completions_menu(
 5785        &mut self,
 5786        requested_source: Option<CompletionsMenuSource>,
 5787        trigger: Option<String>,
 5788        trigger_in_words: bool,
 5789        window: &mut Window,
 5790        cx: &mut Context<Self>,
 5791    ) {
 5792        if self.pending_rename.is_some() {
 5793            return;
 5794        }
 5795
 5796        let completions_source = self
 5797            .context_menu
 5798            .borrow()
 5799            .as_ref()
 5800            .and_then(|menu| match menu {
 5801                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5802                CodeContextMenu::CodeActions(_) => None,
 5803            });
 5804
 5805        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5806
 5807        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5808        // inserted and selected. To handle that case, the start of the selection is used so that
 5809        // the menu starts with all choices.
 5810        let position = self
 5811            .selections
 5812            .newest_anchor()
 5813            .start
 5814            .bias_right(&multibuffer_snapshot);
 5815        if position.diff_base_anchor.is_some() {
 5816            return;
 5817        }
 5818        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5819        let Some(buffer) = buffer_position
 5820            .text_anchor
 5821            .buffer_id
 5822            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5823        else {
 5824            return;
 5825        };
 5826        let buffer_snapshot = buffer.read(cx).snapshot();
 5827
 5828        let menu_is_open = matches!(
 5829            self.context_menu.borrow().as_ref(),
 5830            Some(CodeContextMenu::Completions(_))
 5831        );
 5832
 5833        let language = buffer_snapshot
 5834            .language_at(buffer_position.text_anchor)
 5835            .map(|language| language.name());
 5836
 5837        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5838        let completion_settings = language_settings.completions.clone();
 5839
 5840        let show_completions_on_input = self
 5841            .show_completions_on_input_override
 5842            .unwrap_or(language_settings.show_completions_on_input);
 5843        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5844            return;
 5845        }
 5846
 5847        let query: Option<Arc<String>> =
 5848            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5849                .map(|query| query.into());
 5850
 5851        drop(multibuffer_snapshot);
 5852
 5853        // Hide the current completions menu when query is empty. Without this, cached
 5854        // completions from before the trigger char may be reused (#32774).
 5855        if query.is_none() && menu_is_open {
 5856            self.hide_context_menu(window, cx);
 5857        }
 5858
 5859        let mut ignore_word_threshold = false;
 5860        let provider = match requested_source {
 5861            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5862            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5863                ignore_word_threshold = ignore_threshold;
 5864                None
 5865            }
 5866            Some(CompletionsMenuSource::SnippetChoices)
 5867            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5868                log::error!("bug: SnippetChoices requested_source is not handled");
 5869                None
 5870            }
 5871        };
 5872
 5873        let sort_completions = provider
 5874            .as_ref()
 5875            .is_some_and(|provider| provider.sort_completions());
 5876
 5877        let filter_completions = provider
 5878            .as_ref()
 5879            .is_none_or(|provider| provider.filter_completions());
 5880
 5881        let was_snippets_only = matches!(
 5882            completions_source,
 5883            Some(CompletionsMenuSource::SnippetsOnly)
 5884        );
 5885
 5886        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5887            if filter_completions {
 5888                menu.filter(
 5889                    query.clone().unwrap_or_default(),
 5890                    buffer_position.text_anchor,
 5891                    &buffer,
 5892                    provider.clone(),
 5893                    window,
 5894                    cx,
 5895                );
 5896            }
 5897            // When `is_incomplete` is false, no need to re-query completions when the current query
 5898            // is a suffix of the initial query.
 5899            let was_complete = !menu.is_incomplete;
 5900            if was_complete && !was_snippets_only {
 5901                // If the new query is a suffix of the old query (typing more characters) and
 5902                // the previous result was complete, the existing completions can be filtered.
 5903                //
 5904                // Note that snippet completions are always complete.
 5905                let query_matches = match (&menu.initial_query, &query) {
 5906                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5907                    (None, _) => true,
 5908                    _ => false,
 5909                };
 5910                if query_matches {
 5911                    let position_matches = if menu.initial_position == position {
 5912                        true
 5913                    } else {
 5914                        let snapshot = self.buffer.read(cx).read(cx);
 5915                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5916                    };
 5917                    if position_matches {
 5918                        return;
 5919                    }
 5920                }
 5921            }
 5922        };
 5923
 5924        let Anchor {
 5925            excerpt_id: buffer_excerpt_id,
 5926            text_anchor: buffer_position,
 5927            ..
 5928        } = buffer_position;
 5929
 5930        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5931            buffer_snapshot.surrounding_word(buffer_position, None)
 5932        {
 5933            let word_to_exclude = buffer_snapshot
 5934                .text_for_range(word_range.clone())
 5935                .collect::<String>();
 5936            (
 5937                buffer_snapshot.anchor_before(word_range.start)
 5938                    ..buffer_snapshot.anchor_after(buffer_position),
 5939                Some(word_to_exclude),
 5940            )
 5941        } else {
 5942            (buffer_position..buffer_position, None)
 5943        };
 5944
 5945        let show_completion_documentation = buffer_snapshot
 5946            .settings_at(buffer_position, cx)
 5947            .show_completion_documentation;
 5948
 5949        // The document can be large, so stay in reasonable bounds when searching for words,
 5950        // otherwise completion pop-up might be slow to appear.
 5951        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5952        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5953        let min_word_search = buffer_snapshot.clip_point(
 5954            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5955            Bias::Left,
 5956        );
 5957        let max_word_search = buffer_snapshot.clip_point(
 5958            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5959            Bias::Right,
 5960        );
 5961        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5962            ..buffer_snapshot.point_to_offset(max_word_search);
 5963
 5964        let skip_digits = query
 5965            .as_ref()
 5966            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5967
 5968        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5969            trigger.as_ref().is_none_or(|trigger| {
 5970                provider.is_completion_trigger(
 5971                    &buffer,
 5972                    position.text_anchor,
 5973                    trigger,
 5974                    trigger_in_words,
 5975                    cx,
 5976                )
 5977            })
 5978        });
 5979
 5980        let provider_responses = if let Some(provider) = &provider
 5981            && load_provider_completions
 5982        {
 5983            let trigger_character =
 5984                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5985            let completion_context = CompletionContext {
 5986                trigger_kind: match &trigger_character {
 5987                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5988                    None => CompletionTriggerKind::INVOKED,
 5989                },
 5990                trigger_character,
 5991            };
 5992
 5993            provider.completions(
 5994                buffer_excerpt_id,
 5995                &buffer,
 5996                buffer_position,
 5997                completion_context,
 5998                window,
 5999                cx,
 6000            )
 6001        } else {
 6002            Task::ready(Ok(Vec::new()))
 6003        };
 6004
 6005        let load_word_completions = if !self.word_completions_enabled {
 6006            false
 6007        } else if requested_source
 6008            == Some(CompletionsMenuSource::Words {
 6009                ignore_threshold: true,
 6010            })
 6011        {
 6012            true
 6013        } else {
 6014            load_provider_completions
 6015                && completion_settings.words != WordsCompletionMode::Disabled
 6016                && (ignore_word_threshold || {
 6017                    let words_min_length = completion_settings.words_min_length;
 6018                    // check whether word has at least `words_min_length` characters
 6019                    let query_chars = query.iter().flat_map(|q| q.chars());
 6020                    query_chars.take(words_min_length).count() == words_min_length
 6021                })
 6022        };
 6023
 6024        let mut words = if load_word_completions {
 6025            cx.background_spawn({
 6026                let buffer_snapshot = buffer_snapshot.clone();
 6027                async move {
 6028                    buffer_snapshot.words_in_range(WordsQuery {
 6029                        fuzzy_contents: None,
 6030                        range: word_search_range,
 6031                        skip_digits,
 6032                    })
 6033                }
 6034            })
 6035        } else {
 6036            Task::ready(BTreeMap::default())
 6037        };
 6038
 6039        let snippets = if let Some(provider) = &provider
 6040            && provider.show_snippets()
 6041            && let Some(project) = self.project()
 6042        {
 6043            let char_classifier = buffer_snapshot
 6044                .char_classifier_at(buffer_position)
 6045                .scope_context(Some(CharScopeContext::Completion));
 6046            project.update(cx, |project, cx| {
 6047                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6048            })
 6049        } else {
 6050            Task::ready(Ok(CompletionResponse {
 6051                completions: Vec::new(),
 6052                display_options: Default::default(),
 6053                is_incomplete: false,
 6054            }))
 6055        };
 6056
 6057        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6058
 6059        let id = post_inc(&mut self.next_completion_id);
 6060        let task = cx.spawn_in(window, async move |editor, cx| {
 6061            let Ok(()) = editor.update(cx, |this, _| {
 6062                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6063            }) else {
 6064                return;
 6065            };
 6066
 6067            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6068            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6069            let mut completions = Vec::new();
 6070            let mut is_incomplete = false;
 6071            let mut display_options: Option<CompletionDisplayOptions> = None;
 6072            if let Some(provider_responses) = provider_responses.await.log_err()
 6073                && !provider_responses.is_empty()
 6074            {
 6075                for response in provider_responses {
 6076                    completions.extend(response.completions);
 6077                    is_incomplete = is_incomplete || response.is_incomplete;
 6078                    match display_options.as_mut() {
 6079                        None => {
 6080                            display_options = Some(response.display_options);
 6081                        }
 6082                        Some(options) => options.merge(&response.display_options),
 6083                    }
 6084                }
 6085                if completion_settings.words == WordsCompletionMode::Fallback {
 6086                    words = Task::ready(BTreeMap::default());
 6087                }
 6088            }
 6089            let display_options = display_options.unwrap_or_default();
 6090
 6091            let mut words = words.await;
 6092            if let Some(word_to_exclude) = &word_to_exclude {
 6093                words.remove(word_to_exclude);
 6094            }
 6095            for lsp_completion in &completions {
 6096                words.remove(&lsp_completion.new_text);
 6097            }
 6098            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6099                replace_range: word_replace_range.clone(),
 6100                new_text: word.clone(),
 6101                label: CodeLabel::plain(word, None),
 6102                match_start: None,
 6103                snippet_deduplication_key: None,
 6104                icon_path: None,
 6105                documentation: None,
 6106                source: CompletionSource::BufferWord {
 6107                    word_range,
 6108                    resolved: false,
 6109                },
 6110                insert_text_mode: Some(InsertTextMode::AS_IS),
 6111                confirm: None,
 6112            }));
 6113
 6114            completions.extend(
 6115                snippets
 6116                    .await
 6117                    .into_iter()
 6118                    .flat_map(|response| response.completions),
 6119            );
 6120
 6121            let menu = if completions.is_empty() {
 6122                None
 6123            } else {
 6124                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6125                    let languages = editor
 6126                        .workspace
 6127                        .as_ref()
 6128                        .and_then(|(workspace, _)| workspace.upgrade())
 6129                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6130                    let menu = CompletionsMenu::new(
 6131                        id,
 6132                        requested_source.unwrap_or(if load_provider_completions {
 6133                            CompletionsMenuSource::Normal
 6134                        } else {
 6135                            CompletionsMenuSource::SnippetsOnly
 6136                        }),
 6137                        sort_completions,
 6138                        show_completion_documentation,
 6139                        position,
 6140                        query.clone(),
 6141                        is_incomplete,
 6142                        buffer.clone(),
 6143                        completions.into(),
 6144                        editor
 6145                            .context_menu()
 6146                            .borrow_mut()
 6147                            .as_ref()
 6148                            .map(|menu| menu.primary_scroll_handle()),
 6149                        display_options,
 6150                        snippet_sort_order,
 6151                        languages,
 6152                        language,
 6153                        cx,
 6154                    );
 6155
 6156                    let query = if filter_completions { query } else { None };
 6157                    let matches_task = menu.do_async_filtering(
 6158                        query.unwrap_or_default(),
 6159                        buffer_position,
 6160                        &buffer,
 6161                        cx,
 6162                    );
 6163                    (menu, matches_task)
 6164                }) else {
 6165                    return;
 6166                };
 6167
 6168                let matches = matches_task.await;
 6169
 6170                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6171                    // Newer menu already set, so exit.
 6172                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6173                        editor.context_menu.borrow().as_ref()
 6174                        && prev_menu.id > id
 6175                    {
 6176                        return;
 6177                    };
 6178
 6179                    // Only valid to take prev_menu because either the new menu is immediately set
 6180                    // below, or the menu is hidden.
 6181                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6182                        editor.context_menu.borrow_mut().take()
 6183                    {
 6184                        let position_matches =
 6185                            if prev_menu.initial_position == menu.initial_position {
 6186                                true
 6187                            } else {
 6188                                let snapshot = editor.buffer.read(cx).read(cx);
 6189                                prev_menu.initial_position.to_offset(&snapshot)
 6190                                    == menu.initial_position.to_offset(&snapshot)
 6191                            };
 6192                        if position_matches {
 6193                            // Preserve markdown cache before `set_filter_results` because it will
 6194                            // try to populate the documentation cache.
 6195                            menu.preserve_markdown_cache(prev_menu);
 6196                        }
 6197                    };
 6198
 6199                    menu.set_filter_results(matches, provider, window, cx);
 6200                }) else {
 6201                    return;
 6202                };
 6203
 6204                menu.visible().then_some(menu)
 6205            };
 6206
 6207            editor
 6208                .update_in(cx, |editor, window, cx| {
 6209                    if editor.focus_handle.is_focused(window)
 6210                        && let Some(menu) = menu
 6211                    {
 6212                        *editor.context_menu.borrow_mut() =
 6213                            Some(CodeContextMenu::Completions(menu));
 6214
 6215                        crate::hover_popover::hide_hover(editor, cx);
 6216                        if editor.show_edit_predictions_in_menu() {
 6217                            editor.update_visible_edit_prediction(window, cx);
 6218                        } else {
 6219                            editor
 6220                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6221                        }
 6222
 6223                        cx.notify();
 6224                        return;
 6225                    }
 6226
 6227                    if editor.completion_tasks.len() <= 1 {
 6228                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6229                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6230                        // If it was already hidden and we don't show edit predictions in the menu,
 6231                        // we should also show the edit prediction when available.
 6232                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6233                            editor.update_visible_edit_prediction(window, cx);
 6234                        }
 6235                    }
 6236                })
 6237                .ok();
 6238        });
 6239
 6240        self.completion_tasks.push((id, task));
 6241    }
 6242
 6243    #[cfg(feature = "test-support")]
 6244    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6245        let menu = self.context_menu.borrow();
 6246        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6247            let completions = menu.completions.borrow();
 6248            Some(completions.to_vec())
 6249        } else {
 6250            None
 6251        }
 6252    }
 6253
 6254    pub fn with_completions_menu_matching_id<R>(
 6255        &self,
 6256        id: CompletionId,
 6257        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6258    ) -> R {
 6259        let mut context_menu = self.context_menu.borrow_mut();
 6260        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6261            return f(None);
 6262        };
 6263        if completions_menu.id != id {
 6264            return f(None);
 6265        }
 6266        f(Some(completions_menu))
 6267    }
 6268
 6269    pub fn confirm_completion(
 6270        &mut self,
 6271        action: &ConfirmCompletion,
 6272        window: &mut Window,
 6273        cx: &mut Context<Self>,
 6274    ) -> Option<Task<Result<()>>> {
 6275        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6276        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6277    }
 6278
 6279    pub fn confirm_completion_insert(
 6280        &mut self,
 6281        _: &ConfirmCompletionInsert,
 6282        window: &mut Window,
 6283        cx: &mut Context<Self>,
 6284    ) -> Option<Task<Result<()>>> {
 6285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6286        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6287    }
 6288
 6289    pub fn confirm_completion_replace(
 6290        &mut self,
 6291        _: &ConfirmCompletionReplace,
 6292        window: &mut Window,
 6293        cx: &mut Context<Self>,
 6294    ) -> Option<Task<Result<()>>> {
 6295        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6296        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6297    }
 6298
 6299    pub fn compose_completion(
 6300        &mut self,
 6301        action: &ComposeCompletion,
 6302        window: &mut Window,
 6303        cx: &mut Context<Self>,
 6304    ) -> Option<Task<Result<()>>> {
 6305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6306        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6307    }
 6308
 6309    fn do_completion(
 6310        &mut self,
 6311        item_ix: Option<usize>,
 6312        intent: CompletionIntent,
 6313        window: &mut Window,
 6314        cx: &mut Context<Editor>,
 6315    ) -> Option<Task<Result<()>>> {
 6316        use language::ToOffset as _;
 6317
 6318        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6319        else {
 6320            return None;
 6321        };
 6322
 6323        let candidate_id = {
 6324            let entries = completions_menu.entries.borrow();
 6325            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6326            if self.show_edit_predictions_in_menu() {
 6327                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6328            }
 6329            mat.candidate_id
 6330        };
 6331
 6332        let completion = completions_menu
 6333            .completions
 6334            .borrow()
 6335            .get(candidate_id)?
 6336            .clone();
 6337        cx.stop_propagation();
 6338
 6339        let buffer_handle = completions_menu.buffer.clone();
 6340
 6341        let CompletionEdit {
 6342            new_text,
 6343            snippet,
 6344            replace_range,
 6345        } = process_completion_for_edit(
 6346            &completion,
 6347            intent,
 6348            &buffer_handle,
 6349            &completions_menu.initial_position.text_anchor,
 6350            cx,
 6351        );
 6352
 6353        let buffer = buffer_handle.read(cx);
 6354        let snapshot = self.buffer.read(cx).snapshot(cx);
 6355        let newest_anchor = self.selections.newest_anchor();
 6356        let replace_range_multibuffer = {
 6357            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6358            excerpt.map_range_from_buffer(replace_range.clone())
 6359        };
 6360        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6361            return None;
 6362        }
 6363
 6364        let old_text = buffer
 6365            .text_for_range(replace_range.clone())
 6366            .collect::<String>();
 6367        let lookbehind = newest_anchor
 6368            .start
 6369            .text_anchor
 6370            .to_offset(buffer)
 6371            .saturating_sub(replace_range.start.0);
 6372        let lookahead = replace_range
 6373            .end
 6374            .0
 6375            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6376        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6377        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6378
 6379        let selections = self
 6380            .selections
 6381            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6382        let mut ranges = Vec::new();
 6383        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6384
 6385        for selection in &selections {
 6386            let range = if selection.id == newest_anchor.id {
 6387                replace_range_multibuffer.clone()
 6388            } else {
 6389                let mut range = selection.range();
 6390
 6391                // if prefix is present, don't duplicate it
 6392                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6393                    range.start = range.start.saturating_sub_usize(lookbehind);
 6394
 6395                    // if suffix is also present, mimic the newest cursor and replace it
 6396                    if selection.id != newest_anchor.id
 6397                        && snapshot.contains_str_at(range.end, suffix)
 6398                    {
 6399                        range.end += lookahead;
 6400                    }
 6401                }
 6402                range
 6403            };
 6404
 6405            ranges.push(range.clone());
 6406
 6407            if !self.linked_edit_ranges.is_empty() {
 6408                let start_anchor = snapshot.anchor_before(range.start);
 6409                let end_anchor = snapshot.anchor_after(range.end);
 6410                if let Some(ranges) = self
 6411                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6412                {
 6413                    for (buffer, edits) in ranges {
 6414                        linked_edits
 6415                            .entry(buffer.clone())
 6416                            .or_default()
 6417                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6418                    }
 6419                }
 6420            }
 6421        }
 6422
 6423        let common_prefix_len = old_text
 6424            .chars()
 6425            .zip(new_text.chars())
 6426            .take_while(|(a, b)| a == b)
 6427            .map(|(a, _)| a.len_utf8())
 6428            .sum::<usize>();
 6429
 6430        cx.emit(EditorEvent::InputHandled {
 6431            utf16_range_to_replace: None,
 6432            text: new_text[common_prefix_len..].into(),
 6433        });
 6434
 6435        self.transact(window, cx, |editor, window, cx| {
 6436            if let Some(mut snippet) = snippet {
 6437                snippet.text = new_text.to_string();
 6438                editor
 6439                    .insert_snippet(&ranges, snippet, window, cx)
 6440                    .log_err();
 6441            } else {
 6442                editor.buffer.update(cx, |multi_buffer, cx| {
 6443                    let auto_indent = match completion.insert_text_mode {
 6444                        Some(InsertTextMode::AS_IS) => None,
 6445                        _ => editor.autoindent_mode.clone(),
 6446                    };
 6447                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6448                    multi_buffer.edit(edits, auto_indent, cx);
 6449                });
 6450            }
 6451            for (buffer, edits) in linked_edits {
 6452                buffer.update(cx, |buffer, cx| {
 6453                    let snapshot = buffer.snapshot();
 6454                    let edits = edits
 6455                        .into_iter()
 6456                        .map(|(range, text)| {
 6457                            use text::ToPoint as TP;
 6458                            let end_point = TP::to_point(&range.end, &snapshot);
 6459                            let start_point = TP::to_point(&range.start, &snapshot);
 6460                            (start_point..end_point, text)
 6461                        })
 6462                        .sorted_by_key(|(range, _)| range.start);
 6463                    buffer.edit(edits, None, cx);
 6464                })
 6465            }
 6466
 6467            editor.refresh_edit_prediction(true, false, window, cx);
 6468        });
 6469        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6470
 6471        let show_new_completions_on_confirm = completion
 6472            .confirm
 6473            .as_ref()
 6474            .is_some_and(|confirm| confirm(intent, window, cx));
 6475        if show_new_completions_on_confirm {
 6476            self.open_or_update_completions_menu(None, None, false, window, cx);
 6477        }
 6478
 6479        let provider = self.completion_provider.as_ref()?;
 6480
 6481        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6482        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6483            let CompletionSource::Lsp {
 6484                lsp_completion,
 6485                server_id,
 6486                ..
 6487            } = &completion.source
 6488            else {
 6489                return None;
 6490            };
 6491            let lsp_command = lsp_completion.command.as_ref()?;
 6492            let available_commands = lsp_store
 6493                .read(cx)
 6494                .lsp_server_capabilities
 6495                .get(server_id)
 6496                .and_then(|server_capabilities| {
 6497                    server_capabilities
 6498                        .execute_command_provider
 6499                        .as_ref()
 6500                        .map(|options| options.commands.as_slice())
 6501                })?;
 6502            if available_commands.contains(&lsp_command.command) {
 6503                Some(CodeAction {
 6504                    server_id: *server_id,
 6505                    range: language::Anchor::MIN..language::Anchor::MIN,
 6506                    lsp_action: LspAction::Command(lsp_command.clone()),
 6507                    resolved: false,
 6508                })
 6509            } else {
 6510                None
 6511            }
 6512        });
 6513
 6514        drop(completion);
 6515        let apply_edits = provider.apply_additional_edits_for_completion(
 6516            buffer_handle.clone(),
 6517            completions_menu.completions.clone(),
 6518            candidate_id,
 6519            true,
 6520            cx,
 6521        );
 6522
 6523        let editor_settings = EditorSettings::get_global(cx);
 6524        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6525            // After the code completion is finished, users often want to know what signatures are needed.
 6526            // so we should automatically call signature_help
 6527            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6528        }
 6529
 6530        Some(cx.spawn_in(window, async move |editor, cx| {
 6531            apply_edits.await?;
 6532
 6533            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6534                let title = command.lsp_action.title().to_owned();
 6535                let project_transaction = lsp_store
 6536                    .update(cx, |lsp_store, cx| {
 6537                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6538                    })
 6539                    .await
 6540                    .context("applying post-completion command")?;
 6541                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6542                    Self::open_project_transaction(
 6543                        &editor,
 6544                        workspace.downgrade(),
 6545                        project_transaction,
 6546                        title,
 6547                        cx,
 6548                    )
 6549                    .await?;
 6550                }
 6551            }
 6552
 6553            Ok(())
 6554        }))
 6555    }
 6556
 6557    pub fn toggle_code_actions(
 6558        &mut self,
 6559        action: &ToggleCodeActions,
 6560        window: &mut Window,
 6561        cx: &mut Context<Self>,
 6562    ) {
 6563        let quick_launch = action.quick_launch;
 6564        let mut context_menu = self.context_menu.borrow_mut();
 6565        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6566            if code_actions.deployed_from == action.deployed_from {
 6567                // Toggle if we're selecting the same one
 6568                *context_menu = None;
 6569                cx.notify();
 6570                return;
 6571            } else {
 6572                // Otherwise, clear it and start a new one
 6573                *context_menu = None;
 6574                cx.notify();
 6575            }
 6576        }
 6577        drop(context_menu);
 6578        let snapshot = self.snapshot(window, cx);
 6579        let deployed_from = action.deployed_from.clone();
 6580        let action = action.clone();
 6581        self.completion_tasks.clear();
 6582        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6583
 6584        let multibuffer_point = match &action.deployed_from {
 6585            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6586                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6587            }
 6588            _ => self
 6589                .selections
 6590                .newest::<Point>(&snapshot.display_snapshot)
 6591                .head(),
 6592        };
 6593        let Some((buffer, buffer_row)) = snapshot
 6594            .buffer_snapshot()
 6595            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6596            .and_then(|(buffer_snapshot, range)| {
 6597                self.buffer()
 6598                    .read(cx)
 6599                    .buffer(buffer_snapshot.remote_id())
 6600                    .map(|buffer| (buffer, range.start.row))
 6601            })
 6602        else {
 6603            return;
 6604        };
 6605        let buffer_id = buffer.read(cx).remote_id();
 6606        let tasks = self
 6607            .tasks
 6608            .get(&(buffer_id, buffer_row))
 6609            .map(|t| Arc::new(t.to_owned()));
 6610
 6611        if !self.focus_handle.is_focused(window) {
 6612            return;
 6613        }
 6614        let project = self.project.clone();
 6615
 6616        let code_actions_task = match deployed_from {
 6617            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6618            _ => self.code_actions(buffer_row, window, cx),
 6619        };
 6620
 6621        let runnable_task = match deployed_from {
 6622            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6623            _ => {
 6624                let mut task_context_task = Task::ready(None);
 6625                if let Some(tasks) = &tasks
 6626                    && let Some(project) = project
 6627                {
 6628                    task_context_task =
 6629                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6630                }
 6631
 6632                cx.spawn_in(window, {
 6633                    let buffer = buffer.clone();
 6634                    async move |editor, cx| {
 6635                        let task_context = task_context_task.await;
 6636
 6637                        let resolved_tasks =
 6638                            tasks
 6639                                .zip(task_context.clone())
 6640                                .map(|(tasks, task_context)| ResolvedTasks {
 6641                                    templates: tasks.resolve(&task_context).collect(),
 6642                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6643                                        multibuffer_point.row,
 6644                                        tasks.column,
 6645                                    )),
 6646                                });
 6647                        let debug_scenarios = editor
 6648                            .update(cx, |editor, cx| {
 6649                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6650                            })?
 6651                            .await;
 6652                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6653                    }
 6654                })
 6655            }
 6656        };
 6657
 6658        cx.spawn_in(window, async move |editor, cx| {
 6659            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6660            let code_actions = code_actions_task.await;
 6661            let spawn_straight_away = quick_launch
 6662                && resolved_tasks
 6663                    .as_ref()
 6664                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6665                && code_actions
 6666                    .as_ref()
 6667                    .is_none_or(|actions| actions.is_empty())
 6668                && debug_scenarios.is_empty();
 6669
 6670            editor.update_in(cx, |editor, window, cx| {
 6671                crate::hover_popover::hide_hover(editor, cx);
 6672                let actions = CodeActionContents::new(
 6673                    resolved_tasks,
 6674                    code_actions,
 6675                    debug_scenarios,
 6676                    task_context.unwrap_or_default(),
 6677                );
 6678
 6679                // Don't show the menu if there are no actions available
 6680                if actions.is_empty() {
 6681                    cx.notify();
 6682                    return Task::ready(Ok(()));
 6683                }
 6684
 6685                *editor.context_menu.borrow_mut() =
 6686                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6687                        buffer,
 6688                        actions,
 6689                        selected_item: Default::default(),
 6690                        scroll_handle: UniformListScrollHandle::default(),
 6691                        deployed_from,
 6692                    }));
 6693                cx.notify();
 6694                if spawn_straight_away
 6695                    && let Some(task) = editor.confirm_code_action(
 6696                        &ConfirmCodeAction { item_ix: Some(0) },
 6697                        window,
 6698                        cx,
 6699                    )
 6700                {
 6701                    return task;
 6702                }
 6703
 6704                Task::ready(Ok(()))
 6705            })
 6706        })
 6707        .detach_and_log_err(cx);
 6708    }
 6709
 6710    fn debug_scenarios(
 6711        &mut self,
 6712        resolved_tasks: &Option<ResolvedTasks>,
 6713        buffer: &Entity<Buffer>,
 6714        cx: &mut App,
 6715    ) -> Task<Vec<task::DebugScenario>> {
 6716        maybe!({
 6717            let project = self.project()?;
 6718            let dap_store = project.read(cx).dap_store();
 6719            let mut scenarios = vec![];
 6720            let resolved_tasks = resolved_tasks.as_ref()?;
 6721            let buffer = buffer.read(cx);
 6722            let language = buffer.language()?;
 6723            let file = buffer.file();
 6724            let debug_adapter = language_settings(language.name().into(), file, cx)
 6725                .debuggers
 6726                .first()
 6727                .map(SharedString::from)
 6728                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6729
 6730            dap_store.update(cx, |dap_store, cx| {
 6731                for (_, task) in &resolved_tasks.templates {
 6732                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6733                        task.original_task().clone(),
 6734                        debug_adapter.clone().into(),
 6735                        task.display_label().to_owned().into(),
 6736                        cx,
 6737                    );
 6738                    scenarios.push(maybe_scenario);
 6739                }
 6740            });
 6741            Some(cx.background_spawn(async move {
 6742                futures::future::join_all(scenarios)
 6743                    .await
 6744                    .into_iter()
 6745                    .flatten()
 6746                    .collect::<Vec<_>>()
 6747            }))
 6748        })
 6749        .unwrap_or_else(|| Task::ready(vec![]))
 6750    }
 6751
 6752    fn code_actions(
 6753        &mut self,
 6754        buffer_row: u32,
 6755        window: &mut Window,
 6756        cx: &mut Context<Self>,
 6757    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6758        let mut task = self.code_actions_task.take();
 6759        cx.spawn_in(window, async move |editor, cx| {
 6760            while let Some(prev_task) = task {
 6761                prev_task.await.log_err();
 6762                task = editor
 6763                    .update(cx, |this, _| this.code_actions_task.take())
 6764                    .ok()?;
 6765            }
 6766
 6767            editor
 6768                .update(cx, |editor, cx| {
 6769                    editor
 6770                        .available_code_actions
 6771                        .clone()
 6772                        .and_then(|(location, code_actions)| {
 6773                            let snapshot = location.buffer.read(cx).snapshot();
 6774                            let point_range = location.range.to_point(&snapshot);
 6775                            let point_range = point_range.start.row..=point_range.end.row;
 6776                            if point_range.contains(&buffer_row) {
 6777                                Some(code_actions)
 6778                            } else {
 6779                                None
 6780                            }
 6781                        })
 6782                })
 6783                .ok()
 6784                .flatten()
 6785        })
 6786    }
 6787
 6788    pub fn confirm_code_action(
 6789        &mut self,
 6790        action: &ConfirmCodeAction,
 6791        window: &mut Window,
 6792        cx: &mut Context<Self>,
 6793    ) -> Option<Task<Result<()>>> {
 6794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6795
 6796        let actions_menu =
 6797            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6798                menu
 6799            } else {
 6800                return None;
 6801            };
 6802
 6803        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6804        let action = actions_menu.actions.get(action_ix)?;
 6805        let title = action.label();
 6806        let buffer = actions_menu.buffer;
 6807        let workspace = self.workspace()?;
 6808
 6809        match action {
 6810            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6811                workspace.update(cx, |workspace, cx| {
 6812                    workspace.schedule_resolved_task(
 6813                        task_source_kind,
 6814                        resolved_task,
 6815                        false,
 6816                        window,
 6817                        cx,
 6818                    );
 6819
 6820                    Some(Task::ready(Ok(())))
 6821                })
 6822            }
 6823            CodeActionsItem::CodeAction {
 6824                excerpt_id,
 6825                action,
 6826                provider,
 6827            } => {
 6828                let apply_code_action =
 6829                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6830                let workspace = workspace.downgrade();
 6831                Some(cx.spawn_in(window, async move |editor, cx| {
 6832                    let project_transaction = apply_code_action.await?;
 6833                    Self::open_project_transaction(
 6834                        &editor,
 6835                        workspace,
 6836                        project_transaction,
 6837                        title,
 6838                        cx,
 6839                    )
 6840                    .await
 6841                }))
 6842            }
 6843            CodeActionsItem::DebugScenario(scenario) => {
 6844                let context = actions_menu.actions.context.into();
 6845
 6846                workspace.update(cx, |workspace, cx| {
 6847                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6848                    workspace.start_debug_session(
 6849                        scenario,
 6850                        context,
 6851                        Some(buffer),
 6852                        None,
 6853                        window,
 6854                        cx,
 6855                    );
 6856                });
 6857                Some(Task::ready(Ok(())))
 6858            }
 6859        }
 6860    }
 6861
 6862    fn open_transaction_for_hidden_buffers(
 6863        workspace: Entity<Workspace>,
 6864        transaction: ProjectTransaction,
 6865        title: String,
 6866        window: &mut Window,
 6867        cx: &mut Context<Self>,
 6868    ) {
 6869        if transaction.0.is_empty() {
 6870            return;
 6871        }
 6872
 6873        let edited_buffers_already_open = {
 6874            let other_editors: Vec<Entity<Editor>> = workspace
 6875                .read(cx)
 6876                .panes()
 6877                .iter()
 6878                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6879                .filter(|editor| editor.entity_id() != cx.entity_id())
 6880                .collect();
 6881
 6882            transaction.0.keys().all(|buffer| {
 6883                other_editors.iter().any(|editor| {
 6884                    let multi_buffer = editor.read(cx).buffer();
 6885                    multi_buffer.read(cx).is_singleton()
 6886                        && multi_buffer
 6887                            .read(cx)
 6888                            .as_singleton()
 6889                            .map_or(false, |singleton| {
 6890                                singleton.entity_id() == buffer.entity_id()
 6891                            })
 6892                })
 6893            })
 6894        };
 6895        if !edited_buffers_already_open {
 6896            let workspace = workspace.downgrade();
 6897            cx.defer_in(window, move |_, window, cx| {
 6898                cx.spawn_in(window, async move |editor, cx| {
 6899                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6900                        .await
 6901                        .ok()
 6902                })
 6903                .detach();
 6904            });
 6905        }
 6906    }
 6907
 6908    pub async fn open_project_transaction(
 6909        editor: &WeakEntity<Editor>,
 6910        workspace: WeakEntity<Workspace>,
 6911        transaction: ProjectTransaction,
 6912        title: String,
 6913        cx: &mut AsyncWindowContext,
 6914    ) -> Result<()> {
 6915        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6916        cx.update(|_, cx| {
 6917            entries.sort_unstable_by_key(|(buffer, _)| {
 6918                buffer.read(cx).file().map(|f| f.path().clone())
 6919            });
 6920        })?;
 6921        if entries.is_empty() {
 6922            return Ok(());
 6923        }
 6924
 6925        // If the project transaction's edits are all contained within this editor, then
 6926        // avoid opening a new editor to display them.
 6927
 6928        if let [(buffer, transaction)] = &*entries {
 6929            let excerpt = editor.update(cx, |editor, cx| {
 6930                editor
 6931                    .buffer()
 6932                    .read(cx)
 6933                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6934            })?;
 6935            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6936                && excerpted_buffer == *buffer
 6937            {
 6938                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6939                    let excerpt_range = excerpt_range.to_offset(buffer);
 6940                    buffer
 6941                        .edited_ranges_for_transaction::<usize>(transaction)
 6942                        .all(|range| {
 6943                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6944                        })
 6945                });
 6946
 6947                if all_edits_within_excerpt {
 6948                    return Ok(());
 6949                }
 6950            }
 6951        }
 6952
 6953        let mut ranges_to_highlight = Vec::new();
 6954        let excerpt_buffer = cx.new(|cx| {
 6955            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6956            for (buffer_handle, transaction) in &entries {
 6957                let edited_ranges = buffer_handle
 6958                    .read(cx)
 6959                    .edited_ranges_for_transaction::<Point>(transaction)
 6960                    .collect::<Vec<_>>();
 6961                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6962                    PathKey::for_buffer(buffer_handle, cx),
 6963                    buffer_handle.clone(),
 6964                    edited_ranges,
 6965                    multibuffer_context_lines(cx),
 6966                    cx,
 6967                );
 6968
 6969                ranges_to_highlight.extend(ranges);
 6970            }
 6971            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6972            multibuffer
 6973        });
 6974
 6975        workspace.update_in(cx, |workspace, window, cx| {
 6976            let project = workspace.project().clone();
 6977            let editor =
 6978                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6979            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6980            editor.update(cx, |editor, cx| {
 6981                editor.highlight_background(
 6982                    HighlightKey::Editor,
 6983                    &ranges_to_highlight,
 6984                    |_, theme| theme.colors().editor_highlighted_line_background,
 6985                    cx,
 6986                );
 6987            });
 6988        })?;
 6989
 6990        Ok(())
 6991    }
 6992
 6993    pub fn clear_code_action_providers(&mut self) {
 6994        self.code_action_providers.clear();
 6995        self.available_code_actions.take();
 6996    }
 6997
 6998    pub fn add_code_action_provider(
 6999        &mut self,
 7000        provider: Rc<dyn CodeActionProvider>,
 7001        window: &mut Window,
 7002        cx: &mut Context<Self>,
 7003    ) {
 7004        if self
 7005            .code_action_providers
 7006            .iter()
 7007            .any(|existing_provider| existing_provider.id() == provider.id())
 7008        {
 7009            return;
 7010        }
 7011
 7012        self.code_action_providers.push(provider);
 7013        self.refresh_code_actions(window, cx);
 7014    }
 7015
 7016    pub fn remove_code_action_provider(
 7017        &mut self,
 7018        id: Arc<str>,
 7019        window: &mut Window,
 7020        cx: &mut Context<Self>,
 7021    ) {
 7022        self.code_action_providers
 7023            .retain(|provider| provider.id() != id);
 7024        self.refresh_code_actions(window, cx);
 7025    }
 7026
 7027    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7028        !self.code_action_providers.is_empty()
 7029            && EditorSettings::get_global(cx).toolbar.code_actions
 7030    }
 7031
 7032    pub fn has_available_code_actions(&self) -> bool {
 7033        self.available_code_actions
 7034            .as_ref()
 7035            .is_some_and(|(_, actions)| !actions.is_empty())
 7036    }
 7037
 7038    fn render_inline_code_actions(
 7039        &self,
 7040        icon_size: ui::IconSize,
 7041        display_row: DisplayRow,
 7042        is_active: bool,
 7043        cx: &mut Context<Self>,
 7044    ) -> AnyElement {
 7045        let show_tooltip = !self.context_menu_visible();
 7046        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7047            .icon_size(icon_size)
 7048            .shape(ui::IconButtonShape::Square)
 7049            .icon_color(ui::Color::Hidden)
 7050            .toggle_state(is_active)
 7051            .when(show_tooltip, |this| {
 7052                this.tooltip({
 7053                    let focus_handle = self.focus_handle.clone();
 7054                    move |_window, cx| {
 7055                        Tooltip::for_action_in(
 7056                            "Toggle Code Actions",
 7057                            &ToggleCodeActions {
 7058                                deployed_from: None,
 7059                                quick_launch: false,
 7060                            },
 7061                            &focus_handle,
 7062                            cx,
 7063                        )
 7064                    }
 7065                })
 7066            })
 7067            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7068                window.focus(&editor.focus_handle(cx), cx);
 7069                editor.toggle_code_actions(
 7070                    &crate::actions::ToggleCodeActions {
 7071                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7072                            display_row,
 7073                        )),
 7074                        quick_launch: false,
 7075                    },
 7076                    window,
 7077                    cx,
 7078                );
 7079            }))
 7080            .into_any_element()
 7081    }
 7082
 7083    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7084        &self.context_menu
 7085    }
 7086
 7087    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7088        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7089            cx.background_executor()
 7090                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7091                .await;
 7092
 7093            let (start_buffer, start, _, end, newest_selection) = this
 7094                .update(cx, |this, cx| {
 7095                    let newest_selection = this.selections.newest_anchor().clone();
 7096                    if newest_selection.head().diff_base_anchor.is_some() {
 7097                        return None;
 7098                    }
 7099                    let display_snapshot = this.display_snapshot(cx);
 7100                    let newest_selection_adjusted =
 7101                        this.selections.newest_adjusted(&display_snapshot);
 7102                    let buffer = this.buffer.read(cx);
 7103
 7104                    let (start_buffer, start) =
 7105                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7106                    let (end_buffer, end) =
 7107                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7108
 7109                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7110                })?
 7111                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7112                .context(
 7113                    "Expected selection to lie in a single buffer when refreshing code actions",
 7114                )?;
 7115            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7116                let providers = this.code_action_providers.clone();
 7117                let tasks = this
 7118                    .code_action_providers
 7119                    .iter()
 7120                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7121                    .collect::<Vec<_>>();
 7122                (providers, tasks)
 7123            })?;
 7124
 7125            let mut actions = Vec::new();
 7126            for (provider, provider_actions) in
 7127                providers.into_iter().zip(future::join_all(tasks).await)
 7128            {
 7129                if let Some(provider_actions) = provider_actions.log_err() {
 7130                    actions.extend(provider_actions.into_iter().map(|action| {
 7131                        AvailableCodeAction {
 7132                            excerpt_id: newest_selection.start.excerpt_id,
 7133                            action,
 7134                            provider: provider.clone(),
 7135                        }
 7136                    }));
 7137                }
 7138            }
 7139
 7140            this.update(cx, |this, cx| {
 7141                this.available_code_actions = if actions.is_empty() {
 7142                    None
 7143                } else {
 7144                    Some((
 7145                        Location {
 7146                            buffer: start_buffer,
 7147                            range: start..end,
 7148                        },
 7149                        actions.into(),
 7150                    ))
 7151                };
 7152                cx.notify();
 7153            })
 7154        }));
 7155    }
 7156
 7157    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7158        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7159            self.show_git_blame_inline = false;
 7160
 7161            self.show_git_blame_inline_delay_task =
 7162                Some(cx.spawn_in(window, async move |this, cx| {
 7163                    cx.background_executor().timer(delay).await;
 7164
 7165                    this.update(cx, |this, cx| {
 7166                        this.show_git_blame_inline = true;
 7167                        cx.notify();
 7168                    })
 7169                    .log_err();
 7170                }));
 7171        }
 7172    }
 7173
 7174    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7175        let snapshot = self.snapshot(window, cx);
 7176        let cursor = self
 7177            .selections
 7178            .newest::<Point>(&snapshot.display_snapshot)
 7179            .head();
 7180        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 7181        else {
 7182            return;
 7183        };
 7184
 7185        if self.blame.is_none() {
 7186            self.start_git_blame(true, window, cx);
 7187        }
 7188        let Some(blame) = self.blame.as_ref() else {
 7189            return;
 7190        };
 7191
 7192        let row_info = RowInfo {
 7193            buffer_id: Some(buffer.remote_id()),
 7194            buffer_row: Some(point.row),
 7195            ..Default::default()
 7196        };
 7197        let Some((buffer, blame_entry)) = blame
 7198            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7199            .flatten()
 7200        else {
 7201            return;
 7202        };
 7203
 7204        let anchor = self.selections.newest_anchor().head();
 7205        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7206        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7207            self.show_blame_popover(
 7208                buffer,
 7209                &blame_entry,
 7210                position + last_bounds.origin,
 7211                true,
 7212                cx,
 7213            );
 7214        };
 7215    }
 7216
 7217    fn show_blame_popover(
 7218        &mut self,
 7219        buffer: BufferId,
 7220        blame_entry: &BlameEntry,
 7221        position: gpui::Point<Pixels>,
 7222        ignore_timeout: bool,
 7223        cx: &mut Context<Self>,
 7224    ) {
 7225        if let Some(state) = &mut self.inline_blame_popover {
 7226            state.hide_task.take();
 7227        } else {
 7228            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7229            let blame_entry = blame_entry.clone();
 7230            let show_task = cx.spawn(async move |editor, cx| {
 7231                if !ignore_timeout {
 7232                    cx.background_executor()
 7233                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7234                        .await;
 7235                }
 7236                editor
 7237                    .update(cx, |editor, cx| {
 7238                        editor.inline_blame_popover_show_task.take();
 7239                        let Some(blame) = editor.blame.as_ref() else {
 7240                            return;
 7241                        };
 7242                        let blame = blame.read(cx);
 7243                        let details = blame.details_for_entry(buffer, &blame_entry);
 7244                        let markdown = cx.new(|cx| {
 7245                            Markdown::new(
 7246                                details
 7247                                    .as_ref()
 7248                                    .map(|message| message.message.clone())
 7249                                    .unwrap_or_default(),
 7250                                None,
 7251                                None,
 7252                                cx,
 7253                            )
 7254                        });
 7255                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7256                            position,
 7257                            hide_task: None,
 7258                            popover_bounds: None,
 7259                            popover_state: InlineBlamePopoverState {
 7260                                scroll_handle: ScrollHandle::new(),
 7261                                commit_message: details,
 7262                                markdown,
 7263                            },
 7264                            keyboard_grace: ignore_timeout,
 7265                        });
 7266                        cx.notify();
 7267                    })
 7268                    .ok();
 7269            });
 7270            self.inline_blame_popover_show_task = Some(show_task);
 7271        }
 7272    }
 7273
 7274    pub fn has_mouse_context_menu(&self) -> bool {
 7275        self.mouse_context_menu.is_some()
 7276    }
 7277
 7278    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7279        self.inline_blame_popover_show_task.take();
 7280        if let Some(state) = &mut self.inline_blame_popover {
 7281            let hide_task = cx.spawn(async move |editor, cx| {
 7282                if !ignore_timeout {
 7283                    cx.background_executor()
 7284                        .timer(std::time::Duration::from_millis(100))
 7285                        .await;
 7286                }
 7287                editor
 7288                    .update(cx, |editor, cx| {
 7289                        editor.inline_blame_popover.take();
 7290                        cx.notify();
 7291                    })
 7292                    .ok();
 7293            });
 7294            state.hide_task = Some(hide_task);
 7295            true
 7296        } else {
 7297            false
 7298        }
 7299    }
 7300
 7301    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7302        if self.pending_rename.is_some() {
 7303            return None;
 7304        }
 7305
 7306        let provider = self.semantics_provider.clone()?;
 7307        let buffer = self.buffer.read(cx);
 7308        let newest_selection = self.selections.newest_anchor().clone();
 7309        let cursor_position = newest_selection.head();
 7310        let (cursor_buffer, cursor_buffer_position) =
 7311            buffer.text_anchor_for_position(cursor_position, cx)?;
 7312        let (tail_buffer, tail_buffer_position) =
 7313            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7314        if cursor_buffer != tail_buffer {
 7315            return None;
 7316        }
 7317
 7318        let snapshot = cursor_buffer.read(cx).snapshot();
 7319        let word_ranges = cx.background_spawn(async move {
 7320            // this might look odd to put on the background thread, but
 7321            // `surrounding_word` can be quite expensive as it calls into
 7322            // tree-sitter language scopes
 7323            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7324            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7325            (start_word_range, end_word_range)
 7326        });
 7327
 7328        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7329        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7330            let (start_word_range, end_word_range) = word_ranges.await;
 7331            if start_word_range != end_word_range {
 7332                this.update(cx, |this, cx| {
 7333                    this.document_highlights_task.take();
 7334                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7335                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7336                })
 7337                .ok();
 7338                return;
 7339            }
 7340            cx.background_executor()
 7341                .timer(Duration::from_millis(debounce))
 7342                .await;
 7343
 7344            let highlights = if let Some(highlights) = cx.update(|cx| {
 7345                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7346            }) {
 7347                highlights.await.log_err()
 7348            } else {
 7349                None
 7350            };
 7351
 7352            if let Some(highlights) = highlights {
 7353                this.update(cx, |this, cx| {
 7354                    if this.pending_rename.is_some() {
 7355                        return;
 7356                    }
 7357
 7358                    let buffer = this.buffer.read(cx);
 7359                    if buffer
 7360                        .text_anchor_for_position(cursor_position, cx)
 7361                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7362                    {
 7363                        return;
 7364                    }
 7365
 7366                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7367                    let mut write_ranges = Vec::new();
 7368                    let mut read_ranges = Vec::new();
 7369                    for highlight in highlights {
 7370                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7371                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7372                        {
 7373                            let start = highlight
 7374                                .range
 7375                                .start
 7376                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7377                            let end = highlight
 7378                                .range
 7379                                .end
 7380                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7381                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7382                                continue;
 7383                            }
 7384
 7385                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7386                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7387                                write_ranges.push(range);
 7388                            } else {
 7389                                read_ranges.push(range);
 7390                            }
 7391                        }
 7392                    }
 7393
 7394                    this.highlight_background(
 7395                        HighlightKey::DocumentHighlightRead,
 7396                        &read_ranges,
 7397                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7398                        cx,
 7399                    );
 7400                    this.highlight_background(
 7401                        HighlightKey::DocumentHighlightWrite,
 7402                        &write_ranges,
 7403                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7404                        cx,
 7405                    );
 7406                    cx.notify();
 7407                })
 7408                .log_err();
 7409            }
 7410        }));
 7411        None
 7412    }
 7413
 7414    fn prepare_highlight_query_from_selection(
 7415        &mut self,
 7416        window: &Window,
 7417        cx: &mut Context<Editor>,
 7418    ) -> Option<(String, Range<Anchor>)> {
 7419        if matches!(self.mode, EditorMode::SingleLine) {
 7420            return None;
 7421        }
 7422        if !EditorSettings::get_global(cx).selection_highlight {
 7423            return None;
 7424        }
 7425        if self.selections.count() != 1 || self.selections.line_mode() {
 7426            return None;
 7427        }
 7428        let snapshot = self.snapshot(window, cx);
 7429        let selection = self.selections.newest::<Point>(&snapshot);
 7430        // If the selection spans multiple rows OR it is empty
 7431        if selection.start.row != selection.end.row
 7432            || selection.start.column == selection.end.column
 7433        {
 7434            return None;
 7435        }
 7436        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7437        let query = snapshot
 7438            .buffer_snapshot()
 7439            .text_for_range(selection_anchor_range.clone())
 7440            .collect::<String>();
 7441        if query.trim().is_empty() {
 7442            return None;
 7443        }
 7444        Some((query, selection_anchor_range))
 7445    }
 7446
 7447    #[ztracing::instrument(skip_all)]
 7448    fn update_selection_occurrence_highlights(
 7449        &mut self,
 7450        query_text: String,
 7451        query_range: Range<Anchor>,
 7452        multi_buffer_range_to_query: Range<Point>,
 7453        use_debounce: bool,
 7454        window: &mut Window,
 7455        cx: &mut Context<Editor>,
 7456    ) -> Task<()> {
 7457        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7458        cx.spawn_in(window, async move |editor, cx| {
 7459            if use_debounce {
 7460                cx.background_executor()
 7461                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7462                    .await;
 7463            }
 7464            let match_task = cx.background_spawn(async move {
 7465                let buffer_ranges = multi_buffer_snapshot
 7466                    .range_to_buffer_ranges(
 7467                        multi_buffer_range_to_query.start..=multi_buffer_range_to_query.end,
 7468                    )
 7469                    .into_iter()
 7470                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7471                let mut match_ranges = Vec::new();
 7472                let Ok(regex) = project::search::SearchQuery::text(
 7473                    query_text.clone(),
 7474                    false,
 7475                    false,
 7476                    false,
 7477                    Default::default(),
 7478                    Default::default(),
 7479                    false,
 7480                    None,
 7481                ) else {
 7482                    return Vec::default();
 7483                };
 7484                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7485                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7486                    match_ranges.extend(
 7487                        regex
 7488                            .search(
 7489                                buffer_snapshot,
 7490                                Some(search_range.start.0..search_range.end.0),
 7491                            )
 7492                            .await
 7493                            .into_iter()
 7494                            .filter_map(|match_range| {
 7495                                let match_start = buffer_snapshot
 7496                                    .anchor_after(search_range.start + match_range.start);
 7497                                let match_end = buffer_snapshot
 7498                                    .anchor_before(search_range.start + match_range.end);
 7499                                let match_anchor_range =
 7500                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7501                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7502                            }),
 7503                    );
 7504                }
 7505                match_ranges
 7506            });
 7507            let match_ranges = match_task.await;
 7508            editor
 7509                .update_in(cx, |editor, _, cx| {
 7510                    if use_debounce {
 7511                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7512                        editor.debounced_selection_highlight_complete = true;
 7513                    } else if editor.debounced_selection_highlight_complete {
 7514                        return;
 7515                    }
 7516                    if !match_ranges.is_empty() {
 7517                        editor.highlight_background(
 7518                            HighlightKey::SelectedTextHighlight,
 7519                            &match_ranges,
 7520                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7521                            cx,
 7522                        )
 7523                    }
 7524                })
 7525                .log_err();
 7526        })
 7527    }
 7528
 7529    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7530        struct NewlineFold;
 7531        let type_id = std::any::TypeId::of::<NewlineFold>();
 7532        if !self.mode.is_single_line() {
 7533            return;
 7534        }
 7535        let snapshot = self.snapshot(window, cx);
 7536        if snapshot.buffer_snapshot().max_point().row == 0 {
 7537            return;
 7538        }
 7539        let task = cx.background_spawn(async move {
 7540            let new_newlines = snapshot
 7541                .buffer_chars_at(MultiBufferOffset(0))
 7542                .filter_map(|(c, i)| {
 7543                    if c == '\n' {
 7544                        Some(
 7545                            snapshot.buffer_snapshot().anchor_after(i)
 7546                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7547                        )
 7548                    } else {
 7549                        None
 7550                    }
 7551                })
 7552                .collect::<Vec<_>>();
 7553            let existing_newlines = snapshot
 7554                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7555                .filter_map(|fold| {
 7556                    if fold.placeholder.type_tag == Some(type_id) {
 7557                        Some(fold.range.start..fold.range.end)
 7558                    } else {
 7559                        None
 7560                    }
 7561                })
 7562                .collect::<Vec<_>>();
 7563
 7564            (new_newlines, existing_newlines)
 7565        });
 7566        self.folding_newlines = cx.spawn(async move |this, cx| {
 7567            let (new_newlines, existing_newlines) = task.await;
 7568            if new_newlines == existing_newlines {
 7569                return;
 7570            }
 7571            let placeholder = FoldPlaceholder {
 7572                render: Arc::new(move |_, _, cx| {
 7573                    div()
 7574                        .bg(cx.theme().status().hint_background)
 7575                        .border_b_1()
 7576                        .size_full()
 7577                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7578                        .border_color(cx.theme().status().hint)
 7579                        .child("\\n")
 7580                        .into_any()
 7581                }),
 7582                constrain_width: false,
 7583                merge_adjacent: false,
 7584                type_tag: Some(type_id),
 7585                collapsed_text: None,
 7586            };
 7587            let creases = new_newlines
 7588                .into_iter()
 7589                .map(|range| Crease::simple(range, placeholder.clone()))
 7590                .collect();
 7591            this.update(cx, |this, cx| {
 7592                this.display_map.update(cx, |display_map, cx| {
 7593                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7594                    display_map.fold(creases, cx);
 7595                });
 7596            })
 7597            .ok();
 7598        });
 7599    }
 7600
 7601    #[ztracing::instrument(skip_all)]
 7602    fn refresh_outline_symbols(&mut self, cx: &mut Context<Editor>) {
 7603        if !self.mode.is_full() {
 7604            return;
 7605        }
 7606        let cursor = self.selections.newest_anchor().head();
 7607        let multibuffer = self.buffer().read(cx).snapshot(cx);
 7608        let syntax = cx.theme().syntax().clone();
 7609        let background_task = cx
 7610            .background_spawn(async move { multibuffer.symbols_containing(cursor, Some(&syntax)) });
 7611        self.refresh_outline_symbols_task = cx.spawn(async move |this, cx| {
 7612            let symbols = background_task.await;
 7613            this.update(cx, |this, cx| {
 7614                this.outline_symbols = symbols;
 7615                cx.notify();
 7616            })
 7617            .ok();
 7618        });
 7619    }
 7620
 7621    #[ztracing::instrument(skip_all)]
 7622    fn refresh_selected_text_highlights(
 7623        &mut self,
 7624        on_buffer_edit: bool,
 7625        window: &mut Window,
 7626        cx: &mut Context<Editor>,
 7627    ) {
 7628        let Some((query_text, query_range)) =
 7629            self.prepare_highlight_query_from_selection(window, cx)
 7630        else {
 7631            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7632            self.quick_selection_highlight_task.take();
 7633            self.debounced_selection_highlight_task.take();
 7634            self.debounced_selection_highlight_complete = false;
 7635            return;
 7636        };
 7637        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7638        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7639        let query_changed = self
 7640            .quick_selection_highlight_task
 7641            .as_ref()
 7642            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7643        if query_changed {
 7644            self.debounced_selection_highlight_complete = false;
 7645        }
 7646        if on_buffer_edit || query_changed {
 7647            let multi_buffer_visible_start = self
 7648                .scroll_manager
 7649                .native_anchor(&display_snapshot, cx)
 7650                .anchor
 7651                .to_point(&multi_buffer_snapshot);
 7652            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7653                multi_buffer_visible_start
 7654                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7655                Bias::Left,
 7656            );
 7657            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7658            self.quick_selection_highlight_task = Some((
 7659                query_range.clone(),
 7660                self.update_selection_occurrence_highlights(
 7661                    query_text.clone(),
 7662                    query_range.clone(),
 7663                    multi_buffer_visible_range,
 7664                    false,
 7665                    window,
 7666                    cx,
 7667                ),
 7668            ));
 7669        }
 7670        if on_buffer_edit
 7671            || self
 7672                .debounced_selection_highlight_task
 7673                .as_ref()
 7674                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7675        {
 7676            let multi_buffer_start = multi_buffer_snapshot
 7677                .anchor_before(MultiBufferOffset(0))
 7678                .to_point(&multi_buffer_snapshot);
 7679            let multi_buffer_end = multi_buffer_snapshot
 7680                .anchor_after(multi_buffer_snapshot.len())
 7681                .to_point(&multi_buffer_snapshot);
 7682            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7683            self.debounced_selection_highlight_task = Some((
 7684                query_range.clone(),
 7685                self.update_selection_occurrence_highlights(
 7686                    query_text,
 7687                    query_range,
 7688                    multi_buffer_full_range,
 7689                    true,
 7690                    window,
 7691                    cx,
 7692                ),
 7693            ));
 7694        }
 7695    }
 7696
 7697    pub fn refresh_edit_prediction(
 7698        &mut self,
 7699        debounce: bool,
 7700        user_requested: bool,
 7701        window: &mut Window,
 7702        cx: &mut Context<Self>,
 7703    ) -> Option<()> {
 7704        if DisableAiSettings::get_global(cx).disable_ai {
 7705            return None;
 7706        }
 7707
 7708        let provider = self.edit_prediction_provider()?;
 7709        let cursor = self.selections.newest_anchor().head();
 7710        let (buffer, cursor_buffer_position) =
 7711            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7712
 7713        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7714            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7715            return None;
 7716        }
 7717
 7718        self.update_visible_edit_prediction(window, cx);
 7719
 7720        if !user_requested
 7721            && (!self.should_show_edit_predictions()
 7722                || !self.is_focused(window)
 7723                || buffer.read(cx).is_empty())
 7724        {
 7725            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7726            return None;
 7727        }
 7728
 7729        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7730        Some(())
 7731    }
 7732
 7733    fn show_edit_predictions_in_menu(&self) -> bool {
 7734        match self.edit_prediction_settings {
 7735            EditPredictionSettings::Disabled => false,
 7736            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7737        }
 7738    }
 7739
 7740    pub fn edit_predictions_enabled(&self) -> bool {
 7741        match self.edit_prediction_settings {
 7742            EditPredictionSettings::Disabled => false,
 7743            EditPredictionSettings::Enabled { .. } => true,
 7744        }
 7745    }
 7746
 7747    fn edit_prediction_requires_modifier(&self) -> bool {
 7748        match self.edit_prediction_settings {
 7749            EditPredictionSettings::Disabled => false,
 7750            EditPredictionSettings::Enabled {
 7751                preview_requires_modifier,
 7752                ..
 7753            } => preview_requires_modifier,
 7754        }
 7755    }
 7756
 7757    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7758        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7759            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7760            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7761        } else {
 7762            let selection = self.selections.newest_anchor();
 7763            let cursor = selection.head();
 7764
 7765            if let Some((buffer, cursor_buffer_position)) =
 7766                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7767            {
 7768                self.edit_prediction_settings =
 7769                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7770            }
 7771        }
 7772    }
 7773
 7774    fn edit_prediction_settings_at_position(
 7775        &self,
 7776        buffer: &Entity<Buffer>,
 7777        buffer_position: language::Anchor,
 7778        cx: &App,
 7779    ) -> EditPredictionSettings {
 7780        if !self.mode.is_full()
 7781            || !self.show_edit_predictions_override.unwrap_or(true)
 7782            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7783        {
 7784            return EditPredictionSettings::Disabled;
 7785        }
 7786
 7787        let buffer = buffer.read(cx);
 7788
 7789        let file = buffer.file();
 7790
 7791        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7792            return EditPredictionSettings::Disabled;
 7793        };
 7794
 7795        let by_provider = matches!(
 7796            self.menu_edit_predictions_policy,
 7797            MenuEditPredictionsPolicy::ByProvider
 7798        );
 7799
 7800        let show_in_menu = by_provider
 7801            && self
 7802                .edit_prediction_provider
 7803                .as_ref()
 7804                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7805
 7806        let preview_requires_modifier =
 7807            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7808
 7809        EditPredictionSettings::Enabled {
 7810            show_in_menu,
 7811            preview_requires_modifier,
 7812        }
 7813    }
 7814
 7815    fn should_show_edit_predictions(&self) -> bool {
 7816        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7817    }
 7818
 7819    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7820        matches!(
 7821            self.edit_prediction_preview,
 7822            EditPredictionPreview::Active { .. }
 7823        )
 7824    }
 7825
 7826    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7827        let cursor = self.selections.newest_anchor().head();
 7828        if let Some((buffer, cursor_position)) =
 7829            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7830        {
 7831            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7832        } else {
 7833            false
 7834        }
 7835    }
 7836
 7837    pub fn supports_minimap(&self, cx: &App) -> bool {
 7838        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7839    }
 7840
 7841    fn edit_predictions_enabled_in_buffer(
 7842        &self,
 7843        buffer: &Entity<Buffer>,
 7844        buffer_position: language::Anchor,
 7845        cx: &App,
 7846    ) -> bool {
 7847        maybe!({
 7848            if self.read_only(cx) {
 7849                return Some(false);
 7850            }
 7851            let provider = self.edit_prediction_provider()?;
 7852            if !provider.is_enabled(buffer, buffer_position, cx) {
 7853                return Some(false);
 7854            }
 7855            let buffer = buffer.read(cx);
 7856            let Some(file) = buffer.file() else {
 7857                return Some(true);
 7858            };
 7859            let settings = all_language_settings(Some(file), cx);
 7860            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7861        })
 7862        .unwrap_or(false)
 7863    }
 7864
 7865    pub fn show_edit_prediction(
 7866        &mut self,
 7867        _: &ShowEditPrediction,
 7868        window: &mut Window,
 7869        cx: &mut Context<Self>,
 7870    ) {
 7871        if !self.has_active_edit_prediction() {
 7872            self.refresh_edit_prediction(false, true, window, cx);
 7873            return;
 7874        }
 7875
 7876        self.update_visible_edit_prediction(window, cx);
 7877    }
 7878
 7879    pub fn display_cursor_names(
 7880        &mut self,
 7881        _: &DisplayCursorNames,
 7882        window: &mut Window,
 7883        cx: &mut Context<Self>,
 7884    ) {
 7885        self.show_cursor_names(window, cx);
 7886    }
 7887
 7888    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7889        self.show_cursor_names = true;
 7890        cx.notify();
 7891        cx.spawn_in(window, async move |this, cx| {
 7892            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7893            this.update(cx, |this, cx| {
 7894                this.show_cursor_names = false;
 7895                cx.notify()
 7896            })
 7897            .ok()
 7898        })
 7899        .detach();
 7900    }
 7901
 7902    pub fn accept_partial_edit_prediction(
 7903        &mut self,
 7904        granularity: EditPredictionGranularity,
 7905        window: &mut Window,
 7906        cx: &mut Context<Self>,
 7907    ) {
 7908        if self.show_edit_predictions_in_menu() {
 7909            self.hide_context_menu(window, cx);
 7910        }
 7911
 7912        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7913            return;
 7914        };
 7915
 7916        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7917            return;
 7918        }
 7919
 7920        match &active_edit_prediction.completion {
 7921            EditPrediction::MoveWithin { target, .. } => {
 7922                let target = *target;
 7923
 7924                if matches!(granularity, EditPredictionGranularity::Full) {
 7925                    if let Some(position_map) = &self.last_position_map {
 7926                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7927                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7928
 7929                        if is_visible || !self.edit_prediction_requires_modifier() {
 7930                            self.unfold_ranges(&[target..target], true, false, cx);
 7931                            self.change_selections(
 7932                                SelectionEffects::scroll(Autoscroll::newest()),
 7933                                window,
 7934                                cx,
 7935                                |selections| {
 7936                                    selections.select_anchor_ranges([target..target]);
 7937                                },
 7938                            );
 7939                            self.clear_row_highlights::<EditPredictionPreview>();
 7940                            self.edit_prediction_preview
 7941                                .set_previous_scroll_position(None);
 7942                        } else {
 7943                            // Highlight and request scroll
 7944                            self.edit_prediction_preview
 7945                                .set_previous_scroll_position(Some(
 7946                                    position_map.snapshot.scroll_anchor,
 7947                                ));
 7948                            self.highlight_rows::<EditPredictionPreview>(
 7949                                target..target,
 7950                                cx.theme().colors().editor_highlighted_line_background,
 7951                                RowHighlightOptions {
 7952                                    autoscroll: true,
 7953                                    ..Default::default()
 7954                                },
 7955                                cx,
 7956                            );
 7957                            self.request_autoscroll(Autoscroll::fit(), cx);
 7958                        }
 7959                    }
 7960                } else {
 7961                    self.change_selections(
 7962                        SelectionEffects::scroll(Autoscroll::newest()),
 7963                        window,
 7964                        cx,
 7965                        |selections| {
 7966                            selections.select_anchor_ranges([target..target]);
 7967                        },
 7968                    );
 7969                }
 7970            }
 7971            EditPrediction::MoveOutside { snapshot, target } => {
 7972                if let Some(workspace) = self.workspace() {
 7973                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7974                        .detach_and_log_err(cx);
 7975                }
 7976            }
 7977            EditPrediction::Edit {
 7978                edits,
 7979                cursor_position,
 7980                ..
 7981            } => {
 7982                self.report_edit_prediction_event(
 7983                    active_edit_prediction.completion_id.clone(),
 7984                    true,
 7985                    cx,
 7986                );
 7987
 7988                match granularity {
 7989                    EditPredictionGranularity::Full => {
 7990                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7991
 7992                        // Compute fallback cursor position BEFORE applying the edit,
 7993                        // so the anchor tracks through the edit correctly
 7994                        let fallback_cursor_target = {
 7995                            let snapshot = self.buffer.read(cx).snapshot(cx);
 7996                            edits.last().unwrap().0.end.bias_right(&snapshot)
 7997                        };
 7998
 7999                        self.buffer.update(cx, |buffer, cx| {
 8000                            buffer.edit(edits.iter().cloned(), None, cx)
 8001                        });
 8002
 8003                        if let Some(provider) = self.edit_prediction_provider() {
 8004                            provider.accept(cx);
 8005                        }
 8006
 8007                        // Resolve cursor position after the edit is applied
 8008                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8009                            // The anchor tracks through the edit, then we add the offset
 8010                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8011                            let base_offset = anchor.to_offset(&snapshot).0;
 8012                            let target_offset =
 8013                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8014                            snapshot.anchor_after(target_offset)
 8015                        } else {
 8016                            fallback_cursor_target
 8017                        };
 8018
 8019                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8020                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8021                        });
 8022
 8023                        let selections = self.selections.disjoint_anchors_arc();
 8024                        if let Some(transaction_id_now) =
 8025                            self.buffer.read(cx).last_transaction_id(cx)
 8026                        {
 8027                            if transaction_id_prev != Some(transaction_id_now) {
 8028                                self.selection_history
 8029                                    .insert_transaction(transaction_id_now, selections);
 8030                            }
 8031                        }
 8032
 8033                        self.update_visible_edit_prediction(window, cx);
 8034                        if self.active_edit_prediction.is_none() {
 8035                            self.refresh_edit_prediction(true, true, window, cx);
 8036                        }
 8037                        cx.notify();
 8038                    }
 8039                    _ => {
 8040                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8041                        let cursor_offset = self
 8042                            .selections
 8043                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8044                            .head();
 8045
 8046                        let insertion = edits.iter().find_map(|(range, text)| {
 8047                            let range = range.to_offset(&snapshot);
 8048                            if range.is_empty() && range.start == cursor_offset {
 8049                                Some(text)
 8050                            } else {
 8051                                None
 8052                            }
 8053                        });
 8054
 8055                        if let Some(text) = insertion {
 8056                            let text_to_insert = match granularity {
 8057                                EditPredictionGranularity::Word => {
 8058                                    let mut partial = text
 8059                                        .chars()
 8060                                        .by_ref()
 8061                                        .take_while(|c| c.is_alphabetic())
 8062                                        .collect::<String>();
 8063                                    if partial.is_empty() {
 8064                                        partial = text
 8065                                            .chars()
 8066                                            .by_ref()
 8067                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8068                                            .collect::<String>();
 8069                                    }
 8070                                    partial
 8071                                }
 8072                                EditPredictionGranularity::Line => {
 8073                                    if let Some(line) = text.split_inclusive('\n').next() {
 8074                                        line.to_string()
 8075                                    } else {
 8076                                        text.to_string()
 8077                                    }
 8078                                }
 8079                                EditPredictionGranularity::Full => unreachable!(),
 8080                            };
 8081
 8082                            cx.emit(EditorEvent::InputHandled {
 8083                                utf16_range_to_replace: None,
 8084                                text: text_to_insert.clone().into(),
 8085                            });
 8086
 8087                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 8088                            self.refresh_edit_prediction(true, true, window, cx);
 8089                            cx.notify();
 8090                        } else {
 8091                            self.accept_partial_edit_prediction(
 8092                                EditPredictionGranularity::Full,
 8093                                window,
 8094                                cx,
 8095                            );
 8096                        }
 8097                    }
 8098                }
 8099            }
 8100        }
 8101
 8102        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 8103    }
 8104
 8105    pub fn accept_next_word_edit_prediction(
 8106        &mut self,
 8107        _: &AcceptNextWordEditPrediction,
 8108        window: &mut Window,
 8109        cx: &mut Context<Self>,
 8110    ) {
 8111        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8112    }
 8113
 8114    pub fn accept_next_line_edit_prediction(
 8115        &mut self,
 8116        _: &AcceptNextLineEditPrediction,
 8117        window: &mut Window,
 8118        cx: &mut Context<Self>,
 8119    ) {
 8120        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8121    }
 8122
 8123    pub fn accept_edit_prediction(
 8124        &mut self,
 8125        _: &AcceptEditPrediction,
 8126        window: &mut Window,
 8127        cx: &mut Context<Self>,
 8128    ) {
 8129        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8130    }
 8131
 8132    fn discard_edit_prediction(
 8133        &mut self,
 8134        reason: EditPredictionDiscardReason,
 8135        cx: &mut Context<Self>,
 8136    ) -> bool {
 8137        if reason == EditPredictionDiscardReason::Rejected {
 8138            let completion_id = self
 8139                .active_edit_prediction
 8140                .as_ref()
 8141                .and_then(|active_completion| active_completion.completion_id.clone());
 8142
 8143            self.report_edit_prediction_event(completion_id, false, cx);
 8144        }
 8145
 8146        if let Some(provider) = self.edit_prediction_provider() {
 8147            provider.discard(reason, cx);
 8148        }
 8149
 8150        self.take_active_edit_prediction(cx)
 8151    }
 8152
 8153    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8154        let Some(provider) = self.edit_prediction_provider() else {
 8155            return;
 8156        };
 8157
 8158        let Some((_, buffer, _)) = self
 8159            .buffer
 8160            .read(cx)
 8161            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 8162        else {
 8163            return;
 8164        };
 8165
 8166        let extension = buffer
 8167            .read(cx)
 8168            .file()
 8169            .and_then(|file| Some(file.path().extension()?.to_string()));
 8170
 8171        let event_type = match accepted {
 8172            true => "Edit Prediction Accepted",
 8173            false => "Edit Prediction Discarded",
 8174        };
 8175        telemetry::event!(
 8176            event_type,
 8177            provider = provider.name(),
 8178            prediction_id = id,
 8179            suggestion_accepted = accepted,
 8180            file_extension = extension,
 8181        );
 8182    }
 8183
 8184    fn open_editor_at_anchor(
 8185        snapshot: &language::BufferSnapshot,
 8186        target: language::Anchor,
 8187        workspace: &Entity<Workspace>,
 8188        window: &mut Window,
 8189        cx: &mut App,
 8190    ) -> Task<Result<()>> {
 8191        workspace.update(cx, |workspace, cx| {
 8192            let path = snapshot.file().map(|file| file.full_path(cx));
 8193            let Some(path) =
 8194                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8195            else {
 8196                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8197            };
 8198            let target = text::ToPoint::to_point(&target, snapshot);
 8199            let item = workspace.open_path(path, None, true, window, cx);
 8200            window.spawn(cx, async move |cx| {
 8201                let Some(editor) = item.await?.downcast::<Editor>() else {
 8202                    return Ok(());
 8203                };
 8204                editor
 8205                    .update_in(cx, |editor, window, cx| {
 8206                        editor.go_to_singleton_buffer_point(target, window, cx);
 8207                    })
 8208                    .ok();
 8209                anyhow::Ok(())
 8210            })
 8211        })
 8212    }
 8213
 8214    pub fn has_active_edit_prediction(&self) -> bool {
 8215        self.active_edit_prediction.is_some()
 8216    }
 8217
 8218    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 8219        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8220            return false;
 8221        };
 8222
 8223        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8224        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8225        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 8226        true
 8227    }
 8228
 8229    /// Returns true when we're displaying the edit prediction popover below the cursor
 8230    /// like we are not previewing and the LSP autocomplete menu is visible
 8231    /// or we are in `when_holding_modifier` mode.
 8232    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8233        if self.edit_prediction_preview_is_active()
 8234            || !self.show_edit_predictions_in_menu()
 8235            || !self.edit_predictions_enabled()
 8236        {
 8237            return false;
 8238        }
 8239
 8240        if self.has_visible_completions_menu() {
 8241            return true;
 8242        }
 8243
 8244        has_completion && self.edit_prediction_requires_modifier()
 8245    }
 8246
 8247    fn handle_modifiers_changed(
 8248        &mut self,
 8249        modifiers: Modifiers,
 8250        position_map: &PositionMap,
 8251        window: &mut Window,
 8252        cx: &mut Context<Self>,
 8253    ) {
 8254        // Ensure that the edit prediction preview is updated, even when not
 8255        // enabled, if there's an active edit prediction preview.
 8256        if self.show_edit_predictions_in_menu()
 8257            || matches!(
 8258                self.edit_prediction_preview,
 8259                EditPredictionPreview::Active { .. }
 8260            )
 8261        {
 8262            self.update_edit_prediction_preview(&modifiers, window, cx);
 8263        }
 8264
 8265        self.update_selection_mode(&modifiers, position_map, window, cx);
 8266
 8267        let mouse_position = window.mouse_position();
 8268        if !position_map.text_hitbox.is_hovered(window) {
 8269            return;
 8270        }
 8271
 8272        self.update_hovered_link(
 8273            position_map.point_for_position(mouse_position),
 8274            &position_map.snapshot,
 8275            modifiers,
 8276            window,
 8277            cx,
 8278        )
 8279    }
 8280
 8281    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8282        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8283            MultiCursorModifier::Alt => modifiers.secondary(),
 8284            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8285        }
 8286    }
 8287
 8288    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8289        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8290            MultiCursorModifier::Alt => modifiers.alt,
 8291            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8292        }
 8293    }
 8294
 8295    fn columnar_selection_mode(
 8296        modifiers: &Modifiers,
 8297        cx: &mut Context<Self>,
 8298    ) -> Option<ColumnarMode> {
 8299        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8300            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8301                Some(ColumnarMode::FromMouse)
 8302            } else if Self::is_alt_pressed(modifiers, cx) {
 8303                Some(ColumnarMode::FromSelection)
 8304            } else {
 8305                None
 8306            }
 8307        } else {
 8308            None
 8309        }
 8310    }
 8311
 8312    fn update_selection_mode(
 8313        &mut self,
 8314        modifiers: &Modifiers,
 8315        position_map: &PositionMap,
 8316        window: &mut Window,
 8317        cx: &mut Context<Self>,
 8318    ) {
 8319        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8320            return;
 8321        };
 8322        if self.selections.pending_anchor().is_none() {
 8323            return;
 8324        }
 8325
 8326        let mouse_position = window.mouse_position();
 8327        let point_for_position = position_map.point_for_position(mouse_position);
 8328        let position = point_for_position.previous_valid;
 8329
 8330        self.select(
 8331            SelectPhase::BeginColumnar {
 8332                position,
 8333                reset: false,
 8334                mode,
 8335                goal_column: point_for_position.exact_unclipped.column(),
 8336            },
 8337            window,
 8338            cx,
 8339        );
 8340    }
 8341
 8342    fn update_edit_prediction_preview(
 8343        &mut self,
 8344        modifiers: &Modifiers,
 8345        window: &mut Window,
 8346        cx: &mut Context<Self>,
 8347    ) {
 8348        let mut modifiers_held = false;
 8349
 8350        // Check bindings for all granularities.
 8351        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8352        let granularities = [
 8353            EditPredictionGranularity::Full,
 8354            EditPredictionGranularity::Line,
 8355            EditPredictionGranularity::Word,
 8356        ];
 8357
 8358        for granularity in granularities {
 8359            if let Some(keystroke) = self
 8360                .accept_edit_prediction_keybind(granularity, window, cx)
 8361                .keystroke()
 8362            {
 8363                modifiers_held = modifiers_held
 8364                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8365            }
 8366        }
 8367
 8368        if modifiers_held {
 8369            if matches!(
 8370                self.edit_prediction_preview,
 8371                EditPredictionPreview::Inactive { .. }
 8372            ) {
 8373                self.edit_prediction_preview = EditPredictionPreview::Active {
 8374                    previous_scroll_position: None,
 8375                    since: Instant::now(),
 8376                };
 8377
 8378                self.update_visible_edit_prediction(window, cx);
 8379                cx.notify();
 8380            }
 8381        } else if let EditPredictionPreview::Active {
 8382            previous_scroll_position,
 8383            since,
 8384        } = self.edit_prediction_preview
 8385        {
 8386            if let (Some(previous_scroll_position), Some(position_map)) =
 8387                (previous_scroll_position, self.last_position_map.as_ref())
 8388            {
 8389                self.set_scroll_position(
 8390                    previous_scroll_position
 8391                        .scroll_position(&position_map.snapshot.display_snapshot),
 8392                    window,
 8393                    cx,
 8394                );
 8395            }
 8396
 8397            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8398                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8399            };
 8400            self.clear_row_highlights::<EditPredictionPreview>();
 8401            self.update_visible_edit_prediction(window, cx);
 8402            cx.notify();
 8403        }
 8404    }
 8405
 8406    fn update_visible_edit_prediction(
 8407        &mut self,
 8408        _window: &mut Window,
 8409        cx: &mut Context<Self>,
 8410    ) -> Option<()> {
 8411        if DisableAiSettings::get_global(cx).disable_ai {
 8412            return None;
 8413        }
 8414
 8415        if self.ime_transaction.is_some() {
 8416            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8417            return None;
 8418        }
 8419
 8420        let selection = self.selections.newest_anchor();
 8421        let cursor = selection.head();
 8422        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8423        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8424        let excerpt_id = cursor.excerpt_id;
 8425
 8426        let show_in_menu = self.show_edit_predictions_in_menu();
 8427        let completions_menu_has_precedence = !show_in_menu
 8428            && (self.context_menu.borrow().is_some()
 8429                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8430
 8431        if completions_menu_has_precedence
 8432            || !offset_selection.is_empty()
 8433            || self
 8434                .active_edit_prediction
 8435                .as_ref()
 8436                .is_some_and(|completion| {
 8437                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8438                        return false;
 8439                    };
 8440                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8441                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8442                    !invalidation_range.contains(&offset_selection.head())
 8443                })
 8444        {
 8445            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8446            return None;
 8447        }
 8448
 8449        self.take_active_edit_prediction(cx);
 8450        let Some(provider) = self.edit_prediction_provider() else {
 8451            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8452            return None;
 8453        };
 8454
 8455        let (buffer, cursor_buffer_position) =
 8456            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8457
 8458        self.edit_prediction_settings =
 8459            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8460
 8461        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8462
 8463        if self.edit_prediction_indent_conflict {
 8464            let cursor_point = cursor.to_point(&multibuffer);
 8465            let mut suggested_indent = None;
 8466            multibuffer.suggested_indents_callback(
 8467                cursor_point.row..cursor_point.row + 1,
 8468                |_, indent| {
 8469                    suggested_indent = Some(indent);
 8470                    ControlFlow::Break(())
 8471                },
 8472                cx,
 8473            );
 8474
 8475            if let Some(indent) = suggested_indent
 8476                && indent.len == cursor_point.column
 8477            {
 8478                self.edit_prediction_indent_conflict = false;
 8479            }
 8480        }
 8481
 8482        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8483
 8484        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8485        {
 8486            edit_prediction_types::EditPrediction::Local {
 8487                id,
 8488                edits,
 8489                cursor_position,
 8490                edit_preview,
 8491            } => (id, edits, cursor_position, edit_preview),
 8492            edit_prediction_types::EditPrediction::Jump {
 8493                id,
 8494                snapshot,
 8495                target,
 8496            } => {
 8497                if let Some(provider) = &self.edit_prediction_provider {
 8498                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8499                }
 8500                self.stale_edit_prediction_in_menu = None;
 8501                self.active_edit_prediction = Some(EditPredictionState {
 8502                    inlay_ids: vec![],
 8503                    completion: EditPrediction::MoveOutside { snapshot, target },
 8504                    completion_id: id,
 8505                    invalidation_range: None,
 8506                });
 8507                cx.notify();
 8508                return Some(());
 8509            }
 8510        };
 8511
 8512        let edits = edits
 8513            .into_iter()
 8514            .flat_map(|(range, new_text)| {
 8515                Some((
 8516                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8517                    new_text,
 8518                ))
 8519            })
 8520            .collect::<Vec<_>>();
 8521        if edits.is_empty() {
 8522            return None;
 8523        }
 8524
 8525        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8526            let anchor = multibuffer.anchor_in_excerpt(excerpt_id, predicted.anchor)?;
 8527            Some((anchor, predicted.offset))
 8528        });
 8529
 8530        let first_edit_start = edits.first().unwrap().0.start;
 8531        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8532        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8533
 8534        let last_edit_end = edits.last().unwrap().0.end;
 8535        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8536        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8537
 8538        let cursor_row = cursor.to_point(&multibuffer).row;
 8539
 8540        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8541
 8542        let mut inlay_ids = Vec::new();
 8543        let invalidation_row_range;
 8544        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8545            Some(cursor_row..edit_end_row)
 8546        } else if cursor_row > edit_end_row {
 8547            Some(edit_start_row..cursor_row)
 8548        } else {
 8549            None
 8550        };
 8551        let supports_jump = self
 8552            .edit_prediction_provider
 8553            .as_ref()
 8554            .map(|provider| provider.provider.supports_jump_to_edit())
 8555            .unwrap_or(true);
 8556
 8557        let is_move = supports_jump
 8558            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8559        let completion = if is_move {
 8560            if let Some(provider) = &self.edit_prediction_provider {
 8561                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8562            }
 8563            invalidation_row_range =
 8564                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8565            let target = first_edit_start;
 8566            EditPrediction::MoveWithin { target, snapshot }
 8567        } else {
 8568            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8569                && !self.edit_predictions_hidden_for_vim_mode;
 8570
 8571            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8572                if provider.show_tab_accept_marker() {
 8573                    EditDisplayMode::TabAccept
 8574                } else {
 8575                    EditDisplayMode::Inline
 8576                }
 8577            } else {
 8578                EditDisplayMode::DiffPopover
 8579            };
 8580
 8581            if show_completions_in_buffer {
 8582                if let Some(provider) = &self.edit_prediction_provider {
 8583                    let suggestion_display_type = match display_mode {
 8584                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8585                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8586                            SuggestionDisplayType::GhostText
 8587                        }
 8588                    };
 8589                    provider.provider.did_show(suggestion_display_type, cx);
 8590                }
 8591                if edits
 8592                    .iter()
 8593                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8594                {
 8595                    let mut inlays = Vec::new();
 8596                    for (range, new_text) in &edits {
 8597                        let inlay = Inlay::edit_prediction(
 8598                            post_inc(&mut self.next_inlay_id),
 8599                            range.start,
 8600                            new_text.as_ref(),
 8601                        );
 8602                        inlay_ids.push(inlay.id);
 8603                        inlays.push(inlay);
 8604                    }
 8605
 8606                    self.splice_inlays(&[], inlays, cx);
 8607                } else {
 8608                    let background_color = cx.theme().status().deleted_background;
 8609                    self.highlight_text(
 8610                        HighlightKey::EditPredictionHighlight,
 8611                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8612                        HighlightStyle {
 8613                            background_color: Some(background_color),
 8614                            ..Default::default()
 8615                        },
 8616                        cx,
 8617                    );
 8618                }
 8619            }
 8620
 8621            invalidation_row_range = edit_start_row..edit_end_row;
 8622
 8623            EditPrediction::Edit {
 8624                edits,
 8625                cursor_position,
 8626                edit_preview,
 8627                display_mode,
 8628                snapshot,
 8629            }
 8630        };
 8631
 8632        let invalidation_range = multibuffer
 8633            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8634            ..multibuffer.anchor_after(Point::new(
 8635                invalidation_row_range.end,
 8636                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8637            ));
 8638
 8639        self.stale_edit_prediction_in_menu = None;
 8640        self.active_edit_prediction = Some(EditPredictionState {
 8641            inlay_ids,
 8642            completion,
 8643            completion_id,
 8644            invalidation_range: Some(invalidation_range),
 8645        });
 8646
 8647        cx.notify();
 8648
 8649        Some(())
 8650    }
 8651
 8652    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8653        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8654    }
 8655
 8656    fn clear_tasks(&mut self) {
 8657        self.tasks.clear()
 8658    }
 8659
 8660    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8661        if self.tasks.insert(key, value).is_some() {
 8662            // This case should hopefully be rare, but just in case...
 8663            log::error!(
 8664                "multiple different run targets found on a single line, only the last target will be rendered"
 8665            )
 8666        }
 8667    }
 8668
 8669    /// Get all display points of breakpoints that will be rendered within editor
 8670    ///
 8671    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8672    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8673    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8674    fn active_breakpoints(
 8675        &self,
 8676        range: Range<DisplayRow>,
 8677        window: &mut Window,
 8678        cx: &mut Context<Self>,
 8679    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8680        let mut breakpoint_display_points = HashMap::default();
 8681
 8682        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8683            return breakpoint_display_points;
 8684        };
 8685
 8686        let snapshot = self.snapshot(window, cx);
 8687
 8688        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8689        let Some(project) = self.project() else {
 8690            return breakpoint_display_points;
 8691        };
 8692
 8693        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8694            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8695
 8696        for (buffer_snapshot, range, excerpt_id) in
 8697            multi_buffer_snapshot.range_to_buffer_ranges(range.start..=range.end)
 8698        {
 8699            let Some(buffer) = project
 8700                .read(cx)
 8701                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8702            else {
 8703                continue;
 8704            };
 8705            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8706                &buffer,
 8707                Some(
 8708                    buffer_snapshot.anchor_before(range.start)
 8709                        ..buffer_snapshot.anchor_after(range.end),
 8710                ),
 8711                buffer_snapshot,
 8712                cx,
 8713            );
 8714            for (breakpoint, state) in breakpoints {
 8715                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8716                let position = multi_buffer_anchor
 8717                    .to_point(&multi_buffer_snapshot)
 8718                    .to_display_point(&snapshot);
 8719
 8720                breakpoint_display_points.insert(
 8721                    position.row(),
 8722                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8723                );
 8724            }
 8725        }
 8726
 8727        breakpoint_display_points
 8728    }
 8729
 8730    fn breakpoint_context_menu(
 8731        &self,
 8732        anchor: Anchor,
 8733        window: &mut Window,
 8734        cx: &mut Context<Self>,
 8735    ) -> Entity<ui::ContextMenu> {
 8736        let weak_editor = cx.weak_entity();
 8737        let focus_handle = self.focus_handle(cx);
 8738
 8739        let row = self
 8740            .buffer
 8741            .read(cx)
 8742            .snapshot(cx)
 8743            .summary_for_anchor::<Point>(&anchor)
 8744            .row;
 8745
 8746        let breakpoint = self
 8747            .breakpoint_at_row(row, window, cx)
 8748            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8749
 8750        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8751            "Edit Log Breakpoint"
 8752        } else {
 8753            "Set Log Breakpoint"
 8754        };
 8755
 8756        let condition_breakpoint_msg = if breakpoint
 8757            .as_ref()
 8758            .is_some_and(|bp| bp.1.condition.is_some())
 8759        {
 8760            "Edit Condition Breakpoint"
 8761        } else {
 8762            "Set Condition Breakpoint"
 8763        };
 8764
 8765        let hit_condition_breakpoint_msg = if breakpoint
 8766            .as_ref()
 8767            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8768        {
 8769            "Edit Hit Condition Breakpoint"
 8770        } else {
 8771            "Set Hit Condition Breakpoint"
 8772        };
 8773
 8774        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8775            "Unset Breakpoint"
 8776        } else {
 8777            "Set Breakpoint"
 8778        };
 8779
 8780        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8781
 8782        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8783            BreakpointState::Enabled => Some("Disable"),
 8784            BreakpointState::Disabled => Some("Enable"),
 8785        });
 8786
 8787        let (anchor, breakpoint) =
 8788            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8789
 8790        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8791            menu.on_blur_subscription(Subscription::new(|| {}))
 8792                .context(focus_handle)
 8793                .when(run_to_cursor, |this| {
 8794                    let weak_editor = weak_editor.clone();
 8795                    this.entry("Run to cursor", None, move |window, cx| {
 8796                        weak_editor
 8797                            .update(cx, |editor, cx| {
 8798                                editor.change_selections(
 8799                                    SelectionEffects::no_scroll(),
 8800                                    window,
 8801                                    cx,
 8802                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8803                                );
 8804                            })
 8805                            .ok();
 8806
 8807                        window.dispatch_action(Box::new(RunToCursor), cx);
 8808                    })
 8809                    .separator()
 8810                })
 8811                .when_some(toggle_state_msg, |this, msg| {
 8812                    this.entry(msg, None, {
 8813                        let weak_editor = weak_editor.clone();
 8814                        let breakpoint = breakpoint.clone();
 8815                        move |_window, cx| {
 8816                            weak_editor
 8817                                .update(cx, |this, cx| {
 8818                                    this.edit_breakpoint_at_anchor(
 8819                                        anchor,
 8820                                        breakpoint.as_ref().clone(),
 8821                                        BreakpointEditAction::InvertState,
 8822                                        cx,
 8823                                    );
 8824                                })
 8825                                .log_err();
 8826                        }
 8827                    })
 8828                })
 8829                .entry(set_breakpoint_msg, None, {
 8830                    let weak_editor = weak_editor.clone();
 8831                    let breakpoint = breakpoint.clone();
 8832                    move |_window, cx| {
 8833                        weak_editor
 8834                            .update(cx, |this, cx| {
 8835                                this.edit_breakpoint_at_anchor(
 8836                                    anchor,
 8837                                    breakpoint.as_ref().clone(),
 8838                                    BreakpointEditAction::Toggle,
 8839                                    cx,
 8840                                );
 8841                            })
 8842                            .log_err();
 8843                    }
 8844                })
 8845                .entry(log_breakpoint_msg, None, {
 8846                    let breakpoint = breakpoint.clone();
 8847                    let weak_editor = weak_editor.clone();
 8848                    move |window, cx| {
 8849                        weak_editor
 8850                            .update(cx, |this, cx| {
 8851                                this.add_edit_breakpoint_block(
 8852                                    anchor,
 8853                                    breakpoint.as_ref(),
 8854                                    BreakpointPromptEditAction::Log,
 8855                                    window,
 8856                                    cx,
 8857                                );
 8858                            })
 8859                            .log_err();
 8860                    }
 8861                })
 8862                .entry(condition_breakpoint_msg, None, {
 8863                    let breakpoint = breakpoint.clone();
 8864                    let weak_editor = weak_editor.clone();
 8865                    move |window, cx| {
 8866                        weak_editor
 8867                            .update(cx, |this, cx| {
 8868                                this.add_edit_breakpoint_block(
 8869                                    anchor,
 8870                                    breakpoint.as_ref(),
 8871                                    BreakpointPromptEditAction::Condition,
 8872                                    window,
 8873                                    cx,
 8874                                );
 8875                            })
 8876                            .log_err();
 8877                    }
 8878                })
 8879                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8880                    weak_editor
 8881                        .update(cx, |this, cx| {
 8882                            this.add_edit_breakpoint_block(
 8883                                anchor,
 8884                                breakpoint.as_ref(),
 8885                                BreakpointPromptEditAction::HitCondition,
 8886                                window,
 8887                                cx,
 8888                            );
 8889                        })
 8890                        .log_err();
 8891                })
 8892        })
 8893    }
 8894
 8895    fn render_breakpoint(
 8896        &self,
 8897        position: Anchor,
 8898        row: DisplayRow,
 8899        breakpoint: &Breakpoint,
 8900        state: Option<BreakpointSessionState>,
 8901        cx: &mut Context<Self>,
 8902    ) -> IconButton {
 8903        let is_rejected = state.is_some_and(|s| !s.verified);
 8904        // Is it a breakpoint that shows up when hovering over gutter?
 8905        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8906            (false, false),
 8907            |PhantomBreakpointIndicator {
 8908                 is_active,
 8909                 display_row,
 8910                 collides_with_existing_breakpoint,
 8911             }| {
 8912                (
 8913                    is_active && display_row == row,
 8914                    collides_with_existing_breakpoint,
 8915                )
 8916            },
 8917        );
 8918
 8919        let (color, icon) = {
 8920            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8921                (false, false) => ui::IconName::DebugBreakpoint,
 8922                (true, false) => ui::IconName::DebugLogBreakpoint,
 8923                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8924                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8925            };
 8926
 8927            let theme_colors = cx.theme().colors();
 8928
 8929            let color = if is_phantom {
 8930                if collides_with_existing {
 8931                    Color::Custom(
 8932                        theme_colors
 8933                            .debugger_accent
 8934                            .blend(theme_colors.text.opacity(0.6)),
 8935                    )
 8936                } else {
 8937                    Color::Hint
 8938                }
 8939            } else if is_rejected {
 8940                Color::Disabled
 8941            } else {
 8942                Color::Debugger
 8943            };
 8944
 8945            (color, icon)
 8946        };
 8947
 8948        let breakpoint = Arc::from(breakpoint.clone());
 8949
 8950        let alt_as_text = gpui::Keystroke {
 8951            modifiers: Modifiers::secondary_key(),
 8952            ..Default::default()
 8953        };
 8954        let primary_action_text = if breakpoint.is_disabled() {
 8955            "Enable breakpoint"
 8956        } else if is_phantom && !collides_with_existing {
 8957            "Set breakpoint"
 8958        } else {
 8959            "Unset breakpoint"
 8960        };
 8961        let focus_handle = self.focus_handle.clone();
 8962
 8963        let meta = if is_rejected {
 8964            SharedString::from("No executable code is associated with this line.")
 8965        } else if collides_with_existing && !breakpoint.is_disabled() {
 8966            SharedString::from(format!(
 8967                "{alt_as_text}-click to disable,\nright-click for more options."
 8968            ))
 8969        } else {
 8970            SharedString::from("Right-click for more options.")
 8971        };
 8972        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8973            .icon_size(IconSize::XSmall)
 8974            .size(ui::ButtonSize::None)
 8975            .when(is_rejected, |this| {
 8976                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8977            })
 8978            .icon_color(color)
 8979            .style(ButtonStyle::Transparent)
 8980            .on_click(cx.listener({
 8981                move |editor, event: &ClickEvent, window, cx| {
 8982                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8983                        BreakpointEditAction::InvertState
 8984                    } else {
 8985                        BreakpointEditAction::Toggle
 8986                    };
 8987
 8988                    window.focus(&editor.focus_handle(cx), cx);
 8989                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 8990                    editor.edit_breakpoint_at_anchor(
 8991                        position,
 8992                        breakpoint.as_ref().clone(),
 8993                        edit_action,
 8994                        cx,
 8995                    );
 8996                }
 8997            }))
 8998            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8999                editor.set_breakpoint_context_menu(
 9000                    row,
 9001                    Some(position),
 9002                    event.position(),
 9003                    window,
 9004                    cx,
 9005                );
 9006            }))
 9007            .tooltip(move |_window, cx| {
 9008                Tooltip::with_meta_in(
 9009                    primary_action_text,
 9010                    Some(&ToggleBreakpoint),
 9011                    meta.clone(),
 9012                    &focus_handle,
 9013                    cx,
 9014                )
 9015            })
 9016    }
 9017
 9018    fn build_tasks_context(
 9019        project: &Entity<Project>,
 9020        buffer: &Entity<Buffer>,
 9021        buffer_row: u32,
 9022        tasks: &Arc<RunnableTasks>,
 9023        cx: &mut Context<Self>,
 9024    ) -> Task<Option<task::TaskContext>> {
 9025        let position = Point::new(buffer_row, tasks.column);
 9026        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9027        let location = Location {
 9028            buffer: buffer.clone(),
 9029            range: range_start..range_start,
 9030        };
 9031        // Fill in the environmental variables from the tree-sitter captures
 9032        let mut captured_task_variables = TaskVariables::default();
 9033        for (capture_name, value) in tasks.extra_variables.clone() {
 9034            captured_task_variables.insert(
 9035                task::VariableName::Custom(capture_name.into()),
 9036                value.clone(),
 9037            );
 9038        }
 9039        project.update(cx, |project, cx| {
 9040            project.task_store().update(cx, |task_store, cx| {
 9041                task_store.task_context_for_location(captured_task_variables, location, cx)
 9042            })
 9043        })
 9044    }
 9045
 9046    pub fn spawn_nearest_task(
 9047        &mut self,
 9048        action: &SpawnNearestTask,
 9049        window: &mut Window,
 9050        cx: &mut Context<Self>,
 9051    ) {
 9052        let Some((workspace, _)) = self.workspace.clone() else {
 9053            return;
 9054        };
 9055        let Some(project) = self.project.clone() else {
 9056            return;
 9057        };
 9058
 9059        // Try to find a closest, enclosing node using tree-sitter that has a task
 9060        let Some((buffer, buffer_row, tasks)) = self
 9061            .find_enclosing_node_task(cx)
 9062            // Or find the task that's closest in row-distance.
 9063            .or_else(|| self.find_closest_task(cx))
 9064        else {
 9065            return;
 9066        };
 9067
 9068        let reveal_strategy = action.reveal;
 9069        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 9070        cx.spawn_in(window, async move |_, cx| {
 9071            let context = task_context.await?;
 9072            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 9073
 9074            let resolved = &mut resolved_task.resolved;
 9075            resolved.reveal = reveal_strategy;
 9076
 9077            workspace
 9078                .update_in(cx, |workspace, window, cx| {
 9079                    workspace.schedule_resolved_task(
 9080                        task_source_kind,
 9081                        resolved_task,
 9082                        false,
 9083                        window,
 9084                        cx,
 9085                    );
 9086                })
 9087                .ok()
 9088        })
 9089        .detach();
 9090    }
 9091
 9092    fn find_closest_task(
 9093        &mut self,
 9094        cx: &mut Context<Self>,
 9095    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 9096        let cursor_row = self
 9097            .selections
 9098            .newest_adjusted(&self.display_snapshot(cx))
 9099            .head()
 9100            .row;
 9101
 9102        let ((buffer_id, row), tasks) = self
 9103            .tasks
 9104            .iter()
 9105            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 9106
 9107        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 9108        let tasks = Arc::new(tasks.to_owned());
 9109        Some((buffer, *row, tasks))
 9110    }
 9111
 9112    fn find_enclosing_node_task(
 9113        &mut self,
 9114        cx: &mut Context<Self>,
 9115    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 9116        let snapshot = self.buffer.read(cx).snapshot(cx);
 9117        let offset = self
 9118            .selections
 9119            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 9120            .head();
 9121        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 9122        let offset = excerpt.map_offset_to_buffer(offset);
 9123        let buffer_id = excerpt.buffer().remote_id();
 9124
 9125        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 9126        let mut cursor = layer.node().walk();
 9127
 9128        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 9129            if cursor.node().end_byte() == offset.0 {
 9130                cursor.goto_next_sibling();
 9131            }
 9132        }
 9133
 9134        // Ascend to the smallest ancestor that contains the range and has a task.
 9135        loop {
 9136            let node = cursor.node();
 9137            let node_range = node.byte_range();
 9138            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 9139
 9140            // Check if this node contains our offset
 9141            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 9142                // If it contains offset, check for task
 9143                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 9144                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 9145                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 9146                }
 9147            }
 9148
 9149            if !cursor.goto_parent() {
 9150                break;
 9151            }
 9152        }
 9153        None
 9154    }
 9155
 9156    fn render_run_indicator(
 9157        &self,
 9158        _style: &EditorStyle,
 9159        is_active: bool,
 9160        row: DisplayRow,
 9161        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 9162        cx: &mut Context<Self>,
 9163    ) -> IconButton {
 9164        let color = Color::Muted;
 9165        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 9166
 9167        IconButton::new(
 9168            ("run_indicator", row.0 as usize),
 9169            ui::IconName::PlayOutlined,
 9170        )
 9171        .shape(ui::IconButtonShape::Square)
 9172        .icon_size(IconSize::XSmall)
 9173        .icon_color(color)
 9174        .toggle_state(is_active)
 9175        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 9176            let quick_launch = match e {
 9177                ClickEvent::Keyboard(_) => true,
 9178                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 9179            };
 9180
 9181            window.focus(&editor.focus_handle(cx), cx);
 9182            editor.toggle_code_actions(
 9183                &ToggleCodeActions {
 9184                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 9185                    quick_launch,
 9186                },
 9187                window,
 9188                cx,
 9189            );
 9190        }))
 9191        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9192            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 9193        }))
 9194    }
 9195
 9196    pub fn context_menu_visible(&self) -> bool {
 9197        !self.edit_prediction_preview_is_active()
 9198            && self
 9199                .context_menu
 9200                .borrow()
 9201                .as_ref()
 9202                .is_some_and(|menu| menu.visible())
 9203    }
 9204
 9205    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9206        self.context_menu
 9207            .borrow()
 9208            .as_ref()
 9209            .map(|menu| menu.origin())
 9210    }
 9211
 9212    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9213        self.context_menu_options = Some(options);
 9214    }
 9215
 9216    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9217    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9218
 9219    fn render_edit_prediction_popover(
 9220        &mut self,
 9221        text_bounds: &Bounds<Pixels>,
 9222        content_origin: gpui::Point<Pixels>,
 9223        right_margin: Pixels,
 9224        editor_snapshot: &EditorSnapshot,
 9225        visible_row_range: Range<DisplayRow>,
 9226        scroll_top: ScrollOffset,
 9227        scroll_bottom: ScrollOffset,
 9228        line_layouts: &[LineWithInvisibles],
 9229        line_height: Pixels,
 9230        scroll_position: gpui::Point<ScrollOffset>,
 9231        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9232        newest_selection_head: Option<DisplayPoint>,
 9233        editor_width: Pixels,
 9234        style: &EditorStyle,
 9235        window: &mut Window,
 9236        cx: &mut App,
 9237    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9238        if self.mode().is_minimap() {
 9239            return None;
 9240        }
 9241        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9242
 9243        if self.edit_prediction_visible_in_cursor_popover(true) {
 9244            return None;
 9245        }
 9246
 9247        match &active_edit_prediction.completion {
 9248            EditPrediction::MoveWithin { target, .. } => {
 9249                let target_display_point = target.to_display_point(editor_snapshot);
 9250
 9251                if self.edit_prediction_requires_modifier() {
 9252                    if !self.edit_prediction_preview_is_active() {
 9253                        return None;
 9254                    }
 9255
 9256                    self.render_edit_prediction_modifier_jump_popover(
 9257                        text_bounds,
 9258                        content_origin,
 9259                        visible_row_range,
 9260                        line_layouts,
 9261                        line_height,
 9262                        scroll_pixel_position,
 9263                        newest_selection_head,
 9264                        target_display_point,
 9265                        window,
 9266                        cx,
 9267                    )
 9268                } else {
 9269                    self.render_edit_prediction_eager_jump_popover(
 9270                        text_bounds,
 9271                        content_origin,
 9272                        editor_snapshot,
 9273                        visible_row_range,
 9274                        scroll_top,
 9275                        scroll_bottom,
 9276                        line_height,
 9277                        scroll_pixel_position,
 9278                        target_display_point,
 9279                        editor_width,
 9280                        window,
 9281                        cx,
 9282                    )
 9283                }
 9284            }
 9285            EditPrediction::Edit {
 9286                display_mode: EditDisplayMode::Inline,
 9287                ..
 9288            } => None,
 9289            EditPrediction::Edit {
 9290                display_mode: EditDisplayMode::TabAccept,
 9291                edits,
 9292                ..
 9293            } => {
 9294                let range = &edits.first()?.0;
 9295                let target_display_point = range.end.to_display_point(editor_snapshot);
 9296
 9297                self.render_edit_prediction_end_of_line_popover(
 9298                    "Accept",
 9299                    editor_snapshot,
 9300                    visible_row_range,
 9301                    target_display_point,
 9302                    line_height,
 9303                    scroll_pixel_position,
 9304                    content_origin,
 9305                    editor_width,
 9306                    window,
 9307                    cx,
 9308                )
 9309            }
 9310            EditPrediction::Edit {
 9311                edits,
 9312                edit_preview,
 9313                display_mode: EditDisplayMode::DiffPopover,
 9314                snapshot,
 9315                ..
 9316            } => self.render_edit_prediction_diff_popover(
 9317                text_bounds,
 9318                content_origin,
 9319                right_margin,
 9320                editor_snapshot,
 9321                visible_row_range,
 9322                line_layouts,
 9323                line_height,
 9324                scroll_position,
 9325                scroll_pixel_position,
 9326                newest_selection_head,
 9327                editor_width,
 9328                style,
 9329                edits,
 9330                edit_preview,
 9331                snapshot,
 9332                window,
 9333                cx,
 9334            ),
 9335            EditPrediction::MoveOutside { snapshot, .. } => {
 9336                let mut element = self
 9337                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9338                    .into_any();
 9339
 9340                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9341                let origin_x = text_bounds.size.width - size.width - px(30.);
 9342                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9343                element.prepaint_at(origin, window, cx);
 9344
 9345                Some((element, origin))
 9346            }
 9347        }
 9348    }
 9349
 9350    fn render_edit_prediction_modifier_jump_popover(
 9351        &mut self,
 9352        text_bounds: &Bounds<Pixels>,
 9353        content_origin: gpui::Point<Pixels>,
 9354        visible_row_range: Range<DisplayRow>,
 9355        line_layouts: &[LineWithInvisibles],
 9356        line_height: Pixels,
 9357        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9358        newest_selection_head: Option<DisplayPoint>,
 9359        target_display_point: DisplayPoint,
 9360        window: &mut Window,
 9361        cx: &mut App,
 9362    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9363        let scrolled_content_origin =
 9364            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9365
 9366        const SCROLL_PADDING_Y: Pixels = px(12.);
 9367
 9368        if target_display_point.row() < visible_row_range.start {
 9369            return self.render_edit_prediction_scroll_popover(
 9370                |_| SCROLL_PADDING_Y,
 9371                IconName::ArrowUp,
 9372                visible_row_range,
 9373                line_layouts,
 9374                newest_selection_head,
 9375                scrolled_content_origin,
 9376                window,
 9377                cx,
 9378            );
 9379        } else if target_display_point.row() >= visible_row_range.end {
 9380            return self.render_edit_prediction_scroll_popover(
 9381                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9382                IconName::ArrowDown,
 9383                visible_row_range,
 9384                line_layouts,
 9385                newest_selection_head,
 9386                scrolled_content_origin,
 9387                window,
 9388                cx,
 9389            );
 9390        }
 9391
 9392        const POLE_WIDTH: Pixels = px(2.);
 9393
 9394        let line_layout =
 9395            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9396        let target_column = target_display_point.column() as usize;
 9397
 9398        let target_x = line_layout.x_for_index(target_column);
 9399        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9400            - scroll_pixel_position.y;
 9401
 9402        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9403
 9404        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9405        border_color.l += 0.001;
 9406
 9407        let mut element = v_flex()
 9408            .items_end()
 9409            .when(flag_on_right, |el| el.items_start())
 9410            .child(if flag_on_right {
 9411                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9412                    .rounded_bl(px(0.))
 9413                    .rounded_tl(px(0.))
 9414                    .border_l_2()
 9415                    .border_color(border_color)
 9416            } else {
 9417                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9418                    .rounded_br(px(0.))
 9419                    .rounded_tr(px(0.))
 9420                    .border_r_2()
 9421                    .border_color(border_color)
 9422            })
 9423            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9424            .into_any();
 9425
 9426        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9427
 9428        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9429            - point(
 9430                if flag_on_right {
 9431                    POLE_WIDTH
 9432                } else {
 9433                    size.width - POLE_WIDTH
 9434                },
 9435                size.height - line_height,
 9436            );
 9437
 9438        origin.x = origin.x.max(content_origin.x);
 9439
 9440        element.prepaint_at(origin, window, cx);
 9441
 9442        Some((element, origin))
 9443    }
 9444
 9445    fn render_edit_prediction_scroll_popover(
 9446        &mut self,
 9447        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9448        scroll_icon: IconName,
 9449        visible_row_range: Range<DisplayRow>,
 9450        line_layouts: &[LineWithInvisibles],
 9451        newest_selection_head: Option<DisplayPoint>,
 9452        scrolled_content_origin: gpui::Point<Pixels>,
 9453        window: &mut Window,
 9454        cx: &mut App,
 9455    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9456        let mut element = self
 9457            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9458            .into_any();
 9459
 9460        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9461
 9462        let cursor = newest_selection_head?;
 9463        let cursor_row_layout =
 9464            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9465        let cursor_column = cursor.column() as usize;
 9466
 9467        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9468
 9469        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9470
 9471        element.prepaint_at(origin, window, cx);
 9472        Some((element, origin))
 9473    }
 9474
 9475    fn render_edit_prediction_eager_jump_popover(
 9476        &mut self,
 9477        text_bounds: &Bounds<Pixels>,
 9478        content_origin: gpui::Point<Pixels>,
 9479        editor_snapshot: &EditorSnapshot,
 9480        visible_row_range: Range<DisplayRow>,
 9481        scroll_top: ScrollOffset,
 9482        scroll_bottom: ScrollOffset,
 9483        line_height: Pixels,
 9484        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9485        target_display_point: DisplayPoint,
 9486        editor_width: Pixels,
 9487        window: &mut Window,
 9488        cx: &mut App,
 9489    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9490        if target_display_point.row().as_f64() < scroll_top {
 9491            let mut element = self
 9492                .render_edit_prediction_line_popover(
 9493                    "Jump to Edit",
 9494                    Some(IconName::ArrowUp),
 9495                    window,
 9496                    cx,
 9497                )
 9498                .into_any();
 9499
 9500            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9501            let offset = point(
 9502                (text_bounds.size.width - size.width) / 2.,
 9503                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9504            );
 9505
 9506            let origin = text_bounds.origin + offset;
 9507            element.prepaint_at(origin, window, cx);
 9508            Some((element, origin))
 9509        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9510            let mut element = self
 9511                .render_edit_prediction_line_popover(
 9512                    "Jump to Edit",
 9513                    Some(IconName::ArrowDown),
 9514                    window,
 9515                    cx,
 9516                )
 9517                .into_any();
 9518
 9519            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9520            let offset = point(
 9521                (text_bounds.size.width - size.width) / 2.,
 9522                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9523            );
 9524
 9525            let origin = text_bounds.origin + offset;
 9526            element.prepaint_at(origin, window, cx);
 9527            Some((element, origin))
 9528        } else {
 9529            self.render_edit_prediction_end_of_line_popover(
 9530                "Jump to Edit",
 9531                editor_snapshot,
 9532                visible_row_range,
 9533                target_display_point,
 9534                line_height,
 9535                scroll_pixel_position,
 9536                content_origin,
 9537                editor_width,
 9538                window,
 9539                cx,
 9540            )
 9541        }
 9542    }
 9543
 9544    fn render_edit_prediction_end_of_line_popover(
 9545        self: &mut Editor,
 9546        label: &'static str,
 9547        editor_snapshot: &EditorSnapshot,
 9548        visible_row_range: Range<DisplayRow>,
 9549        target_display_point: DisplayPoint,
 9550        line_height: Pixels,
 9551        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9552        content_origin: gpui::Point<Pixels>,
 9553        editor_width: Pixels,
 9554        window: &mut Window,
 9555        cx: &mut App,
 9556    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9557        let target_line_end = DisplayPoint::new(
 9558            target_display_point.row(),
 9559            editor_snapshot.line_len(target_display_point.row()),
 9560        );
 9561
 9562        let mut element = self
 9563            .render_edit_prediction_line_popover(label, None, window, cx)
 9564            .into_any();
 9565
 9566        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9567
 9568        let line_origin =
 9569            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9570
 9571        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9572        let mut origin = start_point
 9573            + line_origin
 9574            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9575        origin.x = origin.x.max(content_origin.x);
 9576
 9577        let max_x = content_origin.x + editor_width - size.width;
 9578
 9579        if origin.x > max_x {
 9580            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9581
 9582            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9583                origin.y += offset;
 9584                IconName::ArrowUp
 9585            } else {
 9586                origin.y -= offset;
 9587                IconName::ArrowDown
 9588            };
 9589
 9590            element = self
 9591                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9592                .into_any();
 9593
 9594            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9595
 9596            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9597        }
 9598
 9599        element.prepaint_at(origin, window, cx);
 9600        Some((element, origin))
 9601    }
 9602
 9603    fn render_edit_prediction_diff_popover(
 9604        self: &Editor,
 9605        text_bounds: &Bounds<Pixels>,
 9606        content_origin: gpui::Point<Pixels>,
 9607        right_margin: Pixels,
 9608        editor_snapshot: &EditorSnapshot,
 9609        visible_row_range: Range<DisplayRow>,
 9610        line_layouts: &[LineWithInvisibles],
 9611        line_height: Pixels,
 9612        scroll_position: gpui::Point<ScrollOffset>,
 9613        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9614        newest_selection_head: Option<DisplayPoint>,
 9615        editor_width: Pixels,
 9616        style: &EditorStyle,
 9617        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9618        edit_preview: &Option<language::EditPreview>,
 9619        snapshot: &language::BufferSnapshot,
 9620        window: &mut Window,
 9621        cx: &mut App,
 9622    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9623        let edit_start = edits
 9624            .first()
 9625            .unwrap()
 9626            .0
 9627            .start
 9628            .to_display_point(editor_snapshot);
 9629        let edit_end = edits
 9630            .last()
 9631            .unwrap()
 9632            .0
 9633            .end
 9634            .to_display_point(editor_snapshot);
 9635
 9636        let is_visible = visible_row_range.contains(&edit_start.row())
 9637            || visible_row_range.contains(&edit_end.row());
 9638        if !is_visible {
 9639            return None;
 9640        }
 9641
 9642        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9643            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9644        } else {
 9645            // Fallback for providers without edit_preview
 9646            crate::edit_prediction_fallback_text(edits, cx)
 9647        };
 9648
 9649        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9650        let line_count = highlighted_edits.text.lines().count();
 9651
 9652        const BORDER_WIDTH: Pixels = px(1.);
 9653
 9654        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9655        let has_keybind = keybind.is_some();
 9656
 9657        let mut element = h_flex()
 9658            .items_start()
 9659            .child(
 9660                h_flex()
 9661                    .bg(cx.theme().colors().editor_background)
 9662                    .border(BORDER_WIDTH)
 9663                    .shadow_xs()
 9664                    .border_color(cx.theme().colors().border)
 9665                    .rounded_l_lg()
 9666                    .when(line_count > 1, |el| el.rounded_br_lg())
 9667                    .pr_1()
 9668                    .child(styled_text),
 9669            )
 9670            .child(
 9671                h_flex()
 9672                    .h(line_height + BORDER_WIDTH * 2.)
 9673                    .px_1p5()
 9674                    .gap_1()
 9675                    // Workaround: For some reason, there's a gap if we don't do this
 9676                    .ml(-BORDER_WIDTH)
 9677                    .shadow(vec![gpui::BoxShadow {
 9678                        color: gpui::black().opacity(0.05),
 9679                        offset: point(px(1.), px(1.)),
 9680                        blur_radius: px(2.),
 9681                        spread_radius: px(0.),
 9682                    }])
 9683                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9684                    .border(BORDER_WIDTH)
 9685                    .border_color(cx.theme().colors().border)
 9686                    .rounded_r_lg()
 9687                    .id("edit_prediction_diff_popover_keybind")
 9688                    .when(!has_keybind, |el| {
 9689                        let status_colors = cx.theme().status();
 9690
 9691                        el.bg(status_colors.error_background)
 9692                            .border_color(status_colors.error.opacity(0.6))
 9693                            .child(Icon::new(IconName::Info).color(Color::Error))
 9694                            .cursor_default()
 9695                            .hoverable_tooltip(move |_window, cx| {
 9696                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9697                            })
 9698                    })
 9699                    .children(keybind),
 9700            )
 9701            .into_any();
 9702
 9703        let longest_row =
 9704            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9705        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9706            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9707        } else {
 9708            layout_line(
 9709                longest_row,
 9710                editor_snapshot,
 9711                style,
 9712                editor_width,
 9713                |_| false,
 9714                window,
 9715                cx,
 9716            )
 9717            .width
 9718        };
 9719
 9720        let viewport_bounds =
 9721            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9722                right: -right_margin,
 9723                ..Default::default()
 9724            });
 9725
 9726        let x_after_longest = Pixels::from(
 9727            ScrollPixelOffset::from(
 9728                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9729            ) - scroll_pixel_position.x,
 9730        );
 9731
 9732        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9733
 9734        // Fully visible if it can be displayed within the window (allow overlapping other
 9735        // panes). However, this is only allowed if the popover starts within text_bounds.
 9736        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9737            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9738
 9739        let mut origin = if can_position_to_the_right {
 9740            point(
 9741                x_after_longest,
 9742                text_bounds.origin.y
 9743                    + Pixels::from(
 9744                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9745                            - scroll_pixel_position.y,
 9746                    ),
 9747            )
 9748        } else {
 9749            let cursor_row = newest_selection_head.map(|head| head.row());
 9750            let above_edit = edit_start
 9751                .row()
 9752                .0
 9753                .checked_sub(line_count as u32)
 9754                .map(DisplayRow);
 9755            let below_edit = Some(edit_end.row() + 1);
 9756            let above_cursor =
 9757                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9758            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9759
 9760            // Place the edit popover adjacent to the edit if there is a location
 9761            // available that is onscreen and does not obscure the cursor. Otherwise,
 9762            // place it adjacent to the cursor.
 9763            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9764                .into_iter()
 9765                .flatten()
 9766                .find(|&start_row| {
 9767                    let end_row = start_row + line_count as u32;
 9768                    visible_row_range.contains(&start_row)
 9769                        && visible_row_range.contains(&end_row)
 9770                        && cursor_row
 9771                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9772                })?;
 9773
 9774            content_origin
 9775                + point(
 9776                    Pixels::from(-scroll_pixel_position.x),
 9777                    Pixels::from(
 9778                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9779                    ),
 9780                )
 9781        };
 9782
 9783        origin.x -= BORDER_WIDTH;
 9784
 9785        window.defer_draw(element, origin, 1);
 9786
 9787        // Do not return an element, since it will already be drawn due to defer_draw.
 9788        None
 9789    }
 9790
 9791    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9792        px(30.)
 9793    }
 9794
 9795    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9796        if self.read_only(cx) {
 9797            cx.theme().players().read_only()
 9798        } else {
 9799            self.style.as_ref().unwrap().local_player
 9800        }
 9801    }
 9802
 9803    fn render_edit_prediction_accept_keybind(
 9804        &self,
 9805        window: &mut Window,
 9806        cx: &mut App,
 9807    ) -> Option<AnyElement> {
 9808        let accept_binding =
 9809            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9810        let accept_keystroke = accept_binding.keystroke()?;
 9811
 9812        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9813
 9814        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9815            Color::Accent
 9816        } else {
 9817            Color::Muted
 9818        };
 9819
 9820        h_flex()
 9821            .px_0p5()
 9822            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9823            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9824            .text_size(TextSize::XSmall.rems(cx))
 9825            .child(h_flex().children(ui::render_modifiers(
 9826                accept_keystroke.modifiers(),
 9827                PlatformStyle::platform(),
 9828                Some(modifiers_color),
 9829                Some(IconSize::XSmall.rems().into()),
 9830                true,
 9831            )))
 9832            .when(is_platform_style_mac, |parent| {
 9833                parent.child(accept_keystroke.key().to_string())
 9834            })
 9835            .when(!is_platform_style_mac, |parent| {
 9836                parent.child(
 9837                    Key::new(
 9838                        util::capitalize(accept_keystroke.key()),
 9839                        Some(Color::Default),
 9840                    )
 9841                    .size(Some(IconSize::XSmall.rems().into())),
 9842                )
 9843            })
 9844            .into_any()
 9845            .into()
 9846    }
 9847
 9848    fn render_edit_prediction_line_popover(
 9849        &self,
 9850        label: impl Into<SharedString>,
 9851        icon: Option<IconName>,
 9852        window: &mut Window,
 9853        cx: &mut App,
 9854    ) -> Stateful<Div> {
 9855        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9856
 9857        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9858        let has_keybind = keybind.is_some();
 9859        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
 9860
 9861        h_flex()
 9862            .id("ep-line-popover")
 9863            .py_0p5()
 9864            .pl_1()
 9865            .pr(padding_right)
 9866            .gap_1()
 9867            .rounded_md()
 9868            .border_1()
 9869            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9870            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9871            .shadow_xs()
 9872            .when(!has_keybind, |el| {
 9873                let status_colors = cx.theme().status();
 9874
 9875                el.bg(status_colors.error_background)
 9876                    .border_color(status_colors.error.opacity(0.6))
 9877                    .pl_2()
 9878                    .child(Icon::new(icons.error).color(Color::Error))
 9879                    .cursor_default()
 9880                    .hoverable_tooltip(move |_window, cx| {
 9881                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9882                    })
 9883            })
 9884            .children(keybind)
 9885            .child(
 9886                Label::new(label)
 9887                    .size(LabelSize::Small)
 9888                    .when(!has_keybind, |el| {
 9889                        el.color(cx.theme().status().error.into()).strikethrough()
 9890                    }),
 9891            )
 9892            .when(!has_keybind, |el| {
 9893                el.child(
 9894                    h_flex().ml_1().child(
 9895                        Icon::new(IconName::Info)
 9896                            .size(IconSize::Small)
 9897                            .color(cx.theme().status().error.into()),
 9898                    ),
 9899                )
 9900            })
 9901            .when_some(icon, |element, icon| {
 9902                element.child(
 9903                    div()
 9904                        .mt(px(1.5))
 9905                        .child(Icon::new(icon).size(IconSize::Small)),
 9906                )
 9907            })
 9908    }
 9909
 9910    fn render_edit_prediction_jump_outside_popover(
 9911        &self,
 9912        snapshot: &BufferSnapshot,
 9913        window: &mut Window,
 9914        cx: &mut App,
 9915    ) -> Stateful<Div> {
 9916        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9917        let has_keybind = keybind.is_some();
 9918        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
 9919
 9920        let file_name = snapshot
 9921            .file()
 9922            .map(|file| SharedString::new(file.file_name(cx)))
 9923            .unwrap_or(SharedString::new_static("untitled"));
 9924
 9925        h_flex()
 9926            .id("ep-jump-outside-popover")
 9927            .py_1()
 9928            .px_2()
 9929            .gap_1()
 9930            .rounded_md()
 9931            .border_1()
 9932            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9933            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9934            .shadow_xs()
 9935            .when(!has_keybind, |el| {
 9936                let status_colors = cx.theme().status();
 9937
 9938                el.bg(status_colors.error_background)
 9939                    .border_color(status_colors.error.opacity(0.6))
 9940                    .pl_2()
 9941                    .child(Icon::new(icons.error).color(Color::Error))
 9942                    .cursor_default()
 9943                    .hoverable_tooltip(move |_window, cx| {
 9944                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9945                    })
 9946            })
 9947            .children(keybind)
 9948            .child(
 9949                Label::new(file_name)
 9950                    .size(LabelSize::Small)
 9951                    .buffer_font(cx)
 9952                    .when(!has_keybind, |el| {
 9953                        el.color(cx.theme().status().error.into()).strikethrough()
 9954                    }),
 9955            )
 9956            .when(!has_keybind, |el| {
 9957                el.child(
 9958                    h_flex().ml_1().child(
 9959                        Icon::new(IconName::Info)
 9960                            .size(IconSize::Small)
 9961                            .color(cx.theme().status().error.into()),
 9962                    ),
 9963                )
 9964            })
 9965            .child(
 9966                div()
 9967                    .mt(px(1.5))
 9968                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9969            )
 9970    }
 9971
 9972    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9973        let accent_color = cx.theme().colors().text_accent;
 9974        let editor_bg_color = cx.theme().colors().editor_background;
 9975        editor_bg_color.blend(accent_color.opacity(0.1))
 9976    }
 9977
 9978    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9979        let accent_color = cx.theme().colors().text_accent;
 9980        let editor_bg_color = cx.theme().colors().editor_background;
 9981        editor_bg_color.blend(accent_color.opacity(0.6))
 9982    }
 9983    fn get_prediction_provider_icons(
 9984        provider: &Option<RegisteredEditPredictionDelegate>,
 9985        cx: &App,
 9986    ) -> edit_prediction_types::EditPredictionIconSet {
 9987        match provider {
 9988            Some(provider) => provider.provider.icons(cx),
 9989            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
 9990        }
 9991    }
 9992
 9993    fn render_edit_prediction_cursor_popover(
 9994        &self,
 9995        min_width: Pixels,
 9996        max_width: Pixels,
 9997        cursor_point: Point,
 9998        style: &EditorStyle,
 9999        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
10000        _window: &Window,
10001        cx: &mut Context<Editor>,
10002    ) -> Option<AnyElement> {
10003        let provider = self.edit_prediction_provider.as_ref()?;
10004        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10005
10006        let is_refreshing = provider.provider.is_refreshing(cx);
10007
10008        fn pending_completion_container(icon: IconName) -> Div {
10009            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
10010        }
10011
10012        let completion = match &self.active_edit_prediction {
10013            Some(prediction) => {
10014                if !self.has_visible_completions_menu() {
10015                    const RADIUS: Pixels = px(6.);
10016                    const BORDER_WIDTH: Pixels = px(1.);
10017
10018                    return Some(
10019                        h_flex()
10020                            .elevation_2(cx)
10021                            .border(BORDER_WIDTH)
10022                            .border_color(cx.theme().colors().border)
10023                            .when(accept_keystroke.is_none(), |el| {
10024                                el.border_color(cx.theme().status().error)
10025                            })
10026                            .rounded(RADIUS)
10027                            .rounded_tl(px(0.))
10028                            .overflow_hidden()
10029                            .child(div().px_1p5().child(match &prediction.completion {
10030                                EditPrediction::MoveWithin { target, snapshot } => {
10031                                    use text::ToPoint as _;
10032                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
10033                                    {
10034                                        Icon::new(icons.down)
10035                                    } else {
10036                                        Icon::new(icons.up)
10037                                    }
10038                                }
10039                                EditPrediction::MoveOutside { .. } => {
10040                                    // TODO [zeta2] custom icon for external jump?
10041                                    Icon::new(icons.base)
10042                                }
10043                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10044                            }))
10045                            .child(
10046                                h_flex()
10047                                    .gap_1()
10048                                    .py_1()
10049                                    .px_2()
10050                                    .rounded_r(RADIUS - BORDER_WIDTH)
10051                                    .border_l_1()
10052                                    .border_color(cx.theme().colors().border)
10053                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10054                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
10055                                        el.child(
10056                                            Label::new("Hold")
10057                                                .size(LabelSize::Small)
10058                                                .when(accept_keystroke.is_none(), |el| {
10059                                                    el.strikethrough()
10060                                                })
10061                                                .line_height_style(LineHeightStyle::UiLabel),
10062                                        )
10063                                    })
10064                                    .id("edit_prediction_cursor_popover_keybind")
10065                                    .when(accept_keystroke.is_none(), |el| {
10066                                        let status_colors = cx.theme().status();
10067
10068                                        el.bg(status_colors.error_background)
10069                                            .border_color(status_colors.error.opacity(0.6))
10070                                            .child(Icon::new(IconName::Info).color(Color::Error))
10071                                            .cursor_default()
10072                                            .hoverable_tooltip(move |_window, cx| {
10073                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10074                                                    .into()
10075                                            })
10076                                    })
10077                                    .when_some(
10078                                        accept_keystroke.as_ref(),
10079                                        |el, accept_keystroke| {
10080                                            el.child(h_flex().children(ui::render_modifiers(
10081                                                accept_keystroke.modifiers(),
10082                                                PlatformStyle::platform(),
10083                                                Some(Color::Default),
10084                                                Some(IconSize::XSmall.rems().into()),
10085                                                false,
10086                                            )))
10087                                        },
10088                                    ),
10089                            )
10090                            .into_any(),
10091                    );
10092                }
10093
10094                self.render_edit_prediction_cursor_popover_preview(
10095                    prediction,
10096                    cursor_point,
10097                    style,
10098                    cx,
10099                )?
10100            }
10101
10102            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10103                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10104                    stale_completion,
10105                    cursor_point,
10106                    style,
10107                    cx,
10108                )?,
10109
10110                None => pending_completion_container(icons.base)
10111                    .child(Label::new("...").size(LabelSize::Small)),
10112            },
10113
10114            None => pending_completion_container(icons.base)
10115                .child(Label::new("...").size(LabelSize::Small)),
10116        };
10117
10118        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10119            completion
10120                .with_animation(
10121                    "loading-completion",
10122                    Animation::new(Duration::from_secs(2))
10123                        .repeat()
10124                        .with_easing(pulsating_between(0.4, 0.8)),
10125                    |label, delta| label.opacity(delta),
10126                )
10127                .into_any_element()
10128        } else {
10129            completion.into_any_element()
10130        };
10131
10132        let has_completion = self.active_edit_prediction.is_some();
10133
10134        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10135        Some(
10136            h_flex()
10137                .min_w(min_width)
10138                .max_w(max_width)
10139                .flex_1()
10140                .elevation_2(cx)
10141                .border_color(cx.theme().colors().border)
10142                .child(
10143                    div()
10144                        .flex_1()
10145                        .py_1()
10146                        .px_2()
10147                        .overflow_hidden()
10148                        .child(completion),
10149                )
10150                .when_some(accept_keystroke, |el, accept_keystroke| {
10151                    if !accept_keystroke.modifiers().modified() {
10152                        return el;
10153                    }
10154
10155                    el.child(
10156                        h_flex()
10157                            .h_full()
10158                            .border_l_1()
10159                            .rounded_r_lg()
10160                            .border_color(cx.theme().colors().border)
10161                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10162                            .gap_1()
10163                            .py_1()
10164                            .px_2()
10165                            .child(
10166                                h_flex()
10167                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10168                                    .when(is_platform_style_mac, |parent| parent.gap_1())
10169                                    .child(h_flex().children(ui::render_modifiers(
10170                                        accept_keystroke.modifiers(),
10171                                        PlatformStyle::platform(),
10172                                        Some(if !has_completion {
10173                                            Color::Muted
10174                                        } else {
10175                                            Color::Default
10176                                        }),
10177                                        None,
10178                                        false,
10179                                    ))),
10180                            )
10181                            .child(Label::new("Preview").into_any_element())
10182                            .opacity(if has_completion { 1.0 } else { 0.4 }),
10183                    )
10184                })
10185                .into_any(),
10186        )
10187    }
10188
10189    fn render_edit_prediction_cursor_popover_preview(
10190        &self,
10191        completion: &EditPredictionState,
10192        cursor_point: Point,
10193        style: &EditorStyle,
10194        cx: &mut Context<Editor>,
10195    ) -> Option<Div> {
10196        use text::ToPoint as _;
10197
10198        fn render_relative_row_jump(
10199            prefix: impl Into<String>,
10200            current_row: u32,
10201            target_row: u32,
10202        ) -> Div {
10203            let (row_diff, arrow) = if target_row < current_row {
10204                (current_row - target_row, IconName::ArrowUp)
10205            } else {
10206                (target_row - current_row, IconName::ArrowDown)
10207            };
10208
10209            h_flex()
10210                .child(
10211                    Label::new(format!("{}{}", prefix.into(), row_diff))
10212                        .color(Color::Muted)
10213                        .size(LabelSize::Small),
10214                )
10215                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10216        }
10217
10218        let supports_jump = self
10219            .edit_prediction_provider
10220            .as_ref()
10221            .map(|provider| provider.provider.supports_jump_to_edit())
10222            .unwrap_or(true);
10223
10224        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10225
10226        match &completion.completion {
10227            EditPrediction::MoveWithin {
10228                target, snapshot, ..
10229            } => {
10230                if !supports_jump {
10231                    return None;
10232                }
10233
10234                Some(
10235                    h_flex()
10236                        .px_2()
10237                        .gap_2()
10238                        .flex_1()
10239                        .child(
10240                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
10241                                Icon::new(icons.down)
10242                            } else {
10243                                Icon::new(icons.up)
10244                            },
10245                        )
10246                        .child(Label::new("Jump to Edit")),
10247                )
10248            }
10249            EditPrediction::MoveOutside { snapshot, .. } => {
10250                let file_name = snapshot
10251                    .file()
10252                    .map(|file| file.file_name(cx))
10253                    .unwrap_or("untitled");
10254                Some(
10255                    h_flex()
10256                        .px_2()
10257                        .gap_2()
10258                        .flex_1()
10259                        .child(Icon::new(icons.base))
10260                        .child(Label::new(format!("Jump to {file_name}"))),
10261                )
10262            }
10263            EditPrediction::Edit {
10264                edits,
10265                edit_preview,
10266                snapshot,
10267                ..
10268            } => {
10269                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10270
10271                let (highlighted_edits, has_more_lines) =
10272                    if let Some(edit_preview) = edit_preview.as_ref() {
10273                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10274                            .first_line_preview()
10275                    } else {
10276                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10277                    };
10278
10279                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10280                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10281
10282                let preview = h_flex()
10283                    .gap_1()
10284                    .min_w_16()
10285                    .child(styled_text)
10286                    .when(has_more_lines, |parent| parent.child(""));
10287
10288                let left = if supports_jump && first_edit_row != cursor_point.row {
10289                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10290                        .into_any_element()
10291                } else {
10292                    Icon::new(icons.base).into_any_element()
10293                };
10294
10295                Some(
10296                    h_flex()
10297                        .h_full()
10298                        .flex_1()
10299                        .gap_2()
10300                        .pr_1()
10301                        .overflow_x_hidden()
10302                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10303                        .child(left)
10304                        .child(preview),
10305                )
10306            }
10307        }
10308    }
10309
10310    pub fn render_context_menu(
10311        &mut self,
10312        max_height_in_lines: u32,
10313        window: &mut Window,
10314        cx: &mut Context<Editor>,
10315    ) -> Option<AnyElement> {
10316        let menu = self.context_menu.borrow();
10317        let menu = menu.as_ref()?;
10318        if !menu.visible() {
10319            return None;
10320        };
10321        self.style
10322            .as_ref()
10323            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10324    }
10325
10326    fn render_context_menu_aside(
10327        &mut self,
10328        max_size: Size<Pixels>,
10329        window: &mut Window,
10330        cx: &mut Context<Editor>,
10331    ) -> Option<AnyElement> {
10332        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10333            if menu.visible() {
10334                menu.render_aside(max_size, window, cx)
10335            } else {
10336                None
10337            }
10338        })
10339    }
10340
10341    fn hide_context_menu(
10342        &mut self,
10343        window: &mut Window,
10344        cx: &mut Context<Self>,
10345    ) -> Option<CodeContextMenu> {
10346        cx.notify();
10347        self.completion_tasks.clear();
10348        let context_menu = self.context_menu.borrow_mut().take();
10349        self.stale_edit_prediction_in_menu.take();
10350        self.update_visible_edit_prediction(window, cx);
10351        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10352            && let Some(completion_provider) = &self.completion_provider
10353        {
10354            completion_provider.selection_changed(None, window, cx);
10355        }
10356        context_menu
10357    }
10358
10359    fn show_snippet_choices(
10360        &mut self,
10361        choices: &Vec<String>,
10362        selection: Range<Anchor>,
10363        cx: &mut Context<Self>,
10364    ) {
10365        let Some((_, buffer, _)) = self
10366            .buffer()
10367            .read(cx)
10368            .excerpt_containing(selection.start, cx)
10369        else {
10370            return;
10371        };
10372        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10373        else {
10374            return;
10375        };
10376        if buffer != end_buffer {
10377            log::error!("expected anchor range to have matching buffer IDs");
10378            return;
10379        }
10380
10381        let id = post_inc(&mut self.next_completion_id);
10382        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10383        let mut context_menu = self.context_menu.borrow_mut();
10384        let old_menu = context_menu.take();
10385        *context_menu = Some(CodeContextMenu::Completions(
10386            CompletionsMenu::new_snippet_choices(
10387                id,
10388                true,
10389                choices,
10390                selection,
10391                buffer,
10392                old_menu.map(|menu| menu.primary_scroll_handle()),
10393                snippet_sort_order,
10394            ),
10395        ));
10396    }
10397
10398    pub fn insert_snippet(
10399        &mut self,
10400        insertion_ranges: &[Range<MultiBufferOffset>],
10401        snippet: Snippet,
10402        window: &mut Window,
10403        cx: &mut Context<Self>,
10404    ) -> Result<()> {
10405        struct Tabstop<T> {
10406            is_end_tabstop: bool,
10407            ranges: Vec<Range<T>>,
10408            choices: Option<Vec<String>>,
10409        }
10410
10411        let tabstops = self.buffer.update(cx, |buffer, cx| {
10412            let snippet_text: Arc<str> = snippet.text.clone().into();
10413            let edits = insertion_ranges
10414                .iter()
10415                .cloned()
10416                .map(|range| (range, snippet_text.clone()));
10417            let autoindent_mode = AutoindentMode::Block {
10418                original_indent_columns: Vec::new(),
10419            };
10420            buffer.edit(edits, Some(autoindent_mode), cx);
10421
10422            let snapshot = &*buffer.read(cx);
10423            let snippet = &snippet;
10424            snippet
10425                .tabstops
10426                .iter()
10427                .map(|tabstop| {
10428                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10429                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10430                    });
10431                    let mut tabstop_ranges = tabstop
10432                        .ranges
10433                        .iter()
10434                        .flat_map(|tabstop_range| {
10435                            let mut delta = 0_isize;
10436                            insertion_ranges.iter().map(move |insertion_range| {
10437                                let insertion_start = insertion_range.start + delta;
10438                                delta += snippet.text.len() as isize
10439                                    - (insertion_range.end - insertion_range.start) as isize;
10440
10441                                let start =
10442                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10443                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10444                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10445                            })
10446                        })
10447                        .collect::<Vec<_>>();
10448                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10449
10450                    Tabstop {
10451                        is_end_tabstop,
10452                        ranges: tabstop_ranges,
10453                        choices: tabstop.choices.clone(),
10454                    }
10455                })
10456                .collect::<Vec<_>>()
10457        });
10458        if let Some(tabstop) = tabstops.first() {
10459            self.change_selections(Default::default(), window, cx, |s| {
10460                // Reverse order so that the first range is the newest created selection.
10461                // Completions will use it and autoscroll will prioritize it.
10462                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10463            });
10464
10465            if let Some(choices) = &tabstop.choices
10466                && let Some(selection) = tabstop.ranges.first()
10467            {
10468                self.show_snippet_choices(choices, selection.clone(), cx)
10469            }
10470
10471            // If we're already at the last tabstop and it's at the end of the snippet,
10472            // we're done, we don't need to keep the state around.
10473            if !tabstop.is_end_tabstop {
10474                let choices = tabstops
10475                    .iter()
10476                    .map(|tabstop| tabstop.choices.clone())
10477                    .collect();
10478
10479                let ranges = tabstops
10480                    .into_iter()
10481                    .map(|tabstop| tabstop.ranges)
10482                    .collect::<Vec<_>>();
10483
10484                self.snippet_stack.push(SnippetState {
10485                    active_index: 0,
10486                    ranges,
10487                    choices,
10488                });
10489            }
10490
10491            // Check whether the just-entered snippet ends with an auto-closable bracket.
10492            if self.autoclose_regions.is_empty() {
10493                let snapshot = self.buffer.read(cx).snapshot(cx);
10494                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10495                    let selection_head = selection.head();
10496                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10497                        continue;
10498                    };
10499
10500                    let mut bracket_pair = None;
10501                    let max_lookup_length = scope
10502                        .brackets()
10503                        .map(|(pair, _)| {
10504                            pair.start
10505                                .as_str()
10506                                .chars()
10507                                .count()
10508                                .max(pair.end.as_str().chars().count())
10509                        })
10510                        .max();
10511                    if let Some(max_lookup_length) = max_lookup_length {
10512                        let next_text = snapshot
10513                            .chars_at(selection_head)
10514                            .take(max_lookup_length)
10515                            .collect::<String>();
10516                        let prev_text = snapshot
10517                            .reversed_chars_at(selection_head)
10518                            .take(max_lookup_length)
10519                            .collect::<String>();
10520
10521                        for (pair, enabled) in scope.brackets() {
10522                            if enabled
10523                                && pair.close
10524                                && prev_text.starts_with(pair.start.as_str())
10525                                && next_text.starts_with(pair.end.as_str())
10526                            {
10527                                bracket_pair = Some(pair.clone());
10528                                break;
10529                            }
10530                        }
10531                    }
10532
10533                    if let Some(pair) = bracket_pair {
10534                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10535                        let autoclose_enabled =
10536                            self.use_autoclose && snapshot_settings.use_autoclose;
10537                        if autoclose_enabled {
10538                            let start = snapshot.anchor_after(selection_head);
10539                            let end = snapshot.anchor_after(selection_head);
10540                            self.autoclose_regions.push(AutocloseRegion {
10541                                selection_id: selection.id,
10542                                range: start..end,
10543                                pair,
10544                            });
10545                        }
10546                    }
10547                }
10548            }
10549        }
10550        Ok(())
10551    }
10552
10553    pub fn move_to_next_snippet_tabstop(
10554        &mut self,
10555        window: &mut Window,
10556        cx: &mut Context<Self>,
10557    ) -> bool {
10558        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10559    }
10560
10561    pub fn move_to_prev_snippet_tabstop(
10562        &mut self,
10563        window: &mut Window,
10564        cx: &mut Context<Self>,
10565    ) -> bool {
10566        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10567    }
10568
10569    pub fn move_to_snippet_tabstop(
10570        &mut self,
10571        bias: Bias,
10572        window: &mut Window,
10573        cx: &mut Context<Self>,
10574    ) -> bool {
10575        if let Some(mut snippet) = self.snippet_stack.pop() {
10576            match bias {
10577                Bias::Left => {
10578                    if snippet.active_index > 0 {
10579                        snippet.active_index -= 1;
10580                    } else {
10581                        self.snippet_stack.push(snippet);
10582                        return false;
10583                    }
10584                }
10585                Bias::Right => {
10586                    if snippet.active_index + 1 < snippet.ranges.len() {
10587                        snippet.active_index += 1;
10588                    } else {
10589                        self.snippet_stack.push(snippet);
10590                        return false;
10591                    }
10592                }
10593            }
10594            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10595                self.change_selections(Default::default(), window, cx, |s| {
10596                    // Reverse order so that the first range is the newest created selection.
10597                    // Completions will use it and autoscroll will prioritize it.
10598                    s.select_ranges(current_ranges.iter().rev().cloned())
10599                });
10600
10601                if let Some(choices) = &snippet.choices[snippet.active_index]
10602                    && let Some(selection) = current_ranges.first()
10603                {
10604                    self.show_snippet_choices(choices, selection.clone(), cx);
10605                }
10606
10607                // If snippet state is not at the last tabstop, push it back on the stack
10608                if snippet.active_index + 1 < snippet.ranges.len() {
10609                    self.snippet_stack.push(snippet);
10610                }
10611                return true;
10612            }
10613        }
10614
10615        false
10616    }
10617
10618    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10619        self.transact(window, cx, |this, window, cx| {
10620            this.select_all(&SelectAll, window, cx);
10621            this.insert("", window, cx);
10622        });
10623    }
10624
10625    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10626        if self.read_only(cx) {
10627            return;
10628        }
10629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10630        self.transact(window, cx, |this, window, cx| {
10631            this.select_autoclose_pair(window, cx);
10632
10633            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10634
10635            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10636            if !this.linked_edit_ranges.is_empty() {
10637                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10638                let snapshot = this.buffer.read(cx).snapshot(cx);
10639
10640                for selection in selections.iter() {
10641                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10642                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10643                    if selection_start.buffer_id != selection_end.buffer_id {
10644                        continue;
10645                    }
10646                    if let Some(ranges) =
10647                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10648                    {
10649                        for (buffer, entries) in ranges {
10650                            linked_ranges.entry(buffer).or_default().extend(entries);
10651                        }
10652                    }
10653                }
10654            }
10655
10656            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10657            for selection in &mut selections {
10658                if selection.is_empty() {
10659                    let old_head = selection.head();
10660                    let mut new_head =
10661                        movement::left(&display_map, old_head.to_display_point(&display_map))
10662                            .to_point(&display_map);
10663                    if let Some((buffer, line_buffer_range)) = display_map
10664                        .buffer_snapshot()
10665                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10666                    {
10667                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10668                        let indent_len = match indent_size.kind {
10669                            IndentKind::Space => {
10670                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10671                            }
10672                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10673                        };
10674                        if old_head.column <= indent_size.len && old_head.column > 0 {
10675                            let indent_len = indent_len.get();
10676                            new_head = cmp::min(
10677                                new_head,
10678                                MultiBufferPoint::new(
10679                                    old_head.row,
10680                                    ((old_head.column - 1) / indent_len) * indent_len,
10681                                ),
10682                            );
10683                        }
10684                    }
10685
10686                    selection.set_head(new_head, SelectionGoal::None);
10687                }
10688            }
10689
10690            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10691            this.insert("", window, cx);
10692            let empty_str: Arc<str> = Arc::from("");
10693            for (buffer, edits) in linked_ranges {
10694                let snapshot = buffer.read(cx).snapshot();
10695                use text::ToPoint as TP;
10696
10697                let edits = edits
10698                    .into_iter()
10699                    .map(|range| {
10700                        let end_point = TP::to_point(&range.end, &snapshot);
10701                        let mut start_point = TP::to_point(&range.start, &snapshot);
10702
10703                        if end_point == start_point {
10704                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10705                                .saturating_sub(1);
10706                            start_point =
10707                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10708                        };
10709
10710                        (start_point..end_point, empty_str.clone())
10711                    })
10712                    .sorted_by_key(|(range, _)| range.start)
10713                    .collect::<Vec<_>>();
10714                buffer.update(cx, |this, cx| {
10715                    this.edit(edits, None, cx);
10716                })
10717            }
10718            this.refresh_edit_prediction(true, false, window, cx);
10719            refresh_linked_ranges(this, window, cx);
10720        });
10721    }
10722
10723    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10724        if self.read_only(cx) {
10725            return;
10726        }
10727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10728        self.transact(window, cx, |this, window, cx| {
10729            this.change_selections(Default::default(), window, cx, |s| {
10730                s.move_with(|map, selection| {
10731                    if selection.is_empty() {
10732                        let cursor = movement::right(map, selection.head());
10733                        selection.end = cursor;
10734                        selection.reversed = true;
10735                        selection.goal = SelectionGoal::None;
10736                    }
10737                })
10738            });
10739            this.insert("", window, cx);
10740            this.refresh_edit_prediction(true, false, window, cx);
10741        });
10742    }
10743
10744    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10745        if self.mode.is_single_line() {
10746            cx.propagate();
10747            return;
10748        }
10749
10750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10751        if self.move_to_prev_snippet_tabstop(window, cx) {
10752            return;
10753        }
10754        self.outdent(&Outdent, window, cx);
10755    }
10756
10757    pub fn next_snippet_tabstop(
10758        &mut self,
10759        _: &NextSnippetTabstop,
10760        window: &mut Window,
10761        cx: &mut Context<Self>,
10762    ) {
10763        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10764            cx.propagate();
10765            return;
10766        }
10767
10768        if self.move_to_next_snippet_tabstop(window, cx) {
10769            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10770            return;
10771        }
10772        cx.propagate();
10773    }
10774
10775    pub fn previous_snippet_tabstop(
10776        &mut self,
10777        _: &PreviousSnippetTabstop,
10778        window: &mut Window,
10779        cx: &mut Context<Self>,
10780    ) {
10781        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10782            cx.propagate();
10783            return;
10784        }
10785
10786        if self.move_to_prev_snippet_tabstop(window, cx) {
10787            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10788            return;
10789        }
10790        cx.propagate();
10791    }
10792
10793    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10794        if self.mode.is_single_line() {
10795            cx.propagate();
10796            return;
10797        }
10798
10799        if self.move_to_next_snippet_tabstop(window, cx) {
10800            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10801            return;
10802        }
10803        if self.read_only(cx) {
10804            return;
10805        }
10806        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10807        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10808        let buffer = self.buffer.read(cx);
10809        let snapshot = buffer.snapshot(cx);
10810        let rows_iter = selections.iter().map(|s| s.head().row);
10811        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10812
10813        let has_some_cursor_in_whitespace = selections
10814            .iter()
10815            .filter(|selection| selection.is_empty())
10816            .any(|selection| {
10817                let cursor = selection.head();
10818                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10819                cursor.column < current_indent.len
10820            });
10821
10822        let mut edits = Vec::new();
10823        let mut prev_edited_row = 0;
10824        let mut row_delta = 0;
10825        for selection in &mut selections {
10826            if selection.start.row != prev_edited_row {
10827                row_delta = 0;
10828            }
10829            prev_edited_row = selection.end.row;
10830
10831            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10832            if selection.is_empty() {
10833                let cursor = selection.head();
10834                let settings = buffer.language_settings_at(cursor, cx);
10835                if settings.indent_list_on_tab {
10836                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10837                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10838                            row_delta = Self::indent_selection(
10839                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10840                            );
10841                            continue;
10842                        }
10843                    }
10844                }
10845            }
10846
10847            // If the selection is non-empty, then increase the indentation of the selected lines.
10848            if !selection.is_empty() {
10849                row_delta =
10850                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10851                continue;
10852            }
10853
10854            let cursor = selection.head();
10855            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10856            if let Some(suggested_indent) =
10857                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10858            {
10859                // Don't do anything if already at suggested indent
10860                // and there is any other cursor which is not
10861                if has_some_cursor_in_whitespace
10862                    && cursor.column == current_indent.len
10863                    && current_indent.len == suggested_indent.len
10864                {
10865                    continue;
10866                }
10867
10868                // Adjust line and move cursor to suggested indent
10869                // if cursor is not at suggested indent
10870                if cursor.column < suggested_indent.len
10871                    && cursor.column <= current_indent.len
10872                    && current_indent.len <= suggested_indent.len
10873                {
10874                    selection.start = Point::new(cursor.row, suggested_indent.len);
10875                    selection.end = selection.start;
10876                    if row_delta == 0 {
10877                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10878                            cursor.row,
10879                            current_indent,
10880                            suggested_indent,
10881                        ));
10882                        row_delta = suggested_indent.len - current_indent.len;
10883                    }
10884                    continue;
10885                }
10886
10887                // If current indent is more than suggested indent
10888                // only move cursor to current indent and skip indent
10889                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10890                    selection.start = Point::new(cursor.row, current_indent.len);
10891                    selection.end = selection.start;
10892                    continue;
10893                }
10894            }
10895
10896            // Otherwise, insert a hard or soft tab.
10897            let settings = buffer.language_settings_at(cursor, cx);
10898            let tab_size = if settings.hard_tabs {
10899                IndentSize::tab()
10900            } else {
10901                let tab_size = settings.tab_size.get();
10902                let indent_remainder = snapshot
10903                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10904                    .flat_map(str::chars)
10905                    .fold(row_delta % tab_size, |counter: u32, c| {
10906                        if c == '\t' {
10907                            0
10908                        } else {
10909                            (counter + 1) % tab_size
10910                        }
10911                    });
10912
10913                let chars_to_next_tab_stop = tab_size - indent_remainder;
10914                IndentSize::spaces(chars_to_next_tab_stop)
10915            };
10916            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10917            selection.end = selection.start;
10918            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10919            row_delta += tab_size.len;
10920        }
10921
10922        self.transact(window, cx, |this, window, cx| {
10923            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10924            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10925            this.refresh_edit_prediction(true, false, window, cx);
10926        });
10927    }
10928
10929    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10930        if self.read_only(cx) {
10931            return;
10932        }
10933        if self.mode.is_single_line() {
10934            cx.propagate();
10935            return;
10936        }
10937
10938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10939        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10940        let mut prev_edited_row = 0;
10941        let mut row_delta = 0;
10942        let mut edits = Vec::new();
10943        let buffer = self.buffer.read(cx);
10944        let snapshot = buffer.snapshot(cx);
10945        for selection in &mut selections {
10946            if selection.start.row != prev_edited_row {
10947                row_delta = 0;
10948            }
10949            prev_edited_row = selection.end.row;
10950
10951            row_delta =
10952                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10953        }
10954
10955        self.transact(window, cx, |this, window, cx| {
10956            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10957            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10958        });
10959    }
10960
10961    fn indent_selection(
10962        buffer: &MultiBuffer,
10963        snapshot: &MultiBufferSnapshot,
10964        selection: &mut Selection<Point>,
10965        edits: &mut Vec<(Range<Point>, String)>,
10966        delta_for_start_row: u32,
10967        cx: &App,
10968    ) -> u32 {
10969        let settings = buffer.language_settings_at(selection.start, cx);
10970        let tab_size = settings.tab_size.get();
10971        let indent_kind = if settings.hard_tabs {
10972            IndentKind::Tab
10973        } else {
10974            IndentKind::Space
10975        };
10976        let mut start_row = selection.start.row;
10977        let mut end_row = selection.end.row + 1;
10978
10979        // If a selection ends at the beginning of a line, don't indent
10980        // that last line.
10981        if selection.end.column == 0 && selection.end.row > selection.start.row {
10982            end_row -= 1;
10983        }
10984
10985        // Avoid re-indenting a row that has already been indented by a
10986        // previous selection, but still update this selection's column
10987        // to reflect that indentation.
10988        if delta_for_start_row > 0 {
10989            start_row += 1;
10990            selection.start.column += delta_for_start_row;
10991            if selection.end.row == selection.start.row {
10992                selection.end.column += delta_for_start_row;
10993            }
10994        }
10995
10996        let mut delta_for_end_row = 0;
10997        let has_multiple_rows = start_row + 1 != end_row;
10998        for row in start_row..end_row {
10999            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
11000            let indent_delta = match (current_indent.kind, indent_kind) {
11001                (IndentKind::Space, IndentKind::Space) => {
11002                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
11003                    IndentSize::spaces(columns_to_next_tab_stop)
11004                }
11005                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
11006                (_, IndentKind::Tab) => IndentSize::tab(),
11007            };
11008
11009            let start = if has_multiple_rows || current_indent.len < selection.start.column {
11010                0
11011            } else {
11012                selection.start.column
11013            };
11014            let row_start = Point::new(row, start);
11015            edits.push((
11016                row_start..row_start,
11017                indent_delta.chars().collect::<String>(),
11018            ));
11019
11020            // Update this selection's endpoints to reflect the indentation.
11021            if row == selection.start.row {
11022                selection.start.column += indent_delta.len;
11023            }
11024            if row == selection.end.row {
11025                selection.end.column += indent_delta.len;
11026                delta_for_end_row = indent_delta.len;
11027            }
11028        }
11029
11030        if selection.start.row == selection.end.row {
11031            delta_for_start_row + delta_for_end_row
11032        } else {
11033            delta_for_end_row
11034        }
11035    }
11036
11037    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
11038        if self.read_only(cx) {
11039            return;
11040        }
11041        if self.mode.is_single_line() {
11042            cx.propagate();
11043            return;
11044        }
11045
11046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11047        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11048        let selections = self.selections.all::<Point>(&display_map);
11049        let mut deletion_ranges = Vec::new();
11050        let mut last_outdent = None;
11051        {
11052            let buffer = self.buffer.read(cx);
11053            let snapshot = buffer.snapshot(cx);
11054            for selection in &selections {
11055                let settings = buffer.language_settings_at(selection.start, cx);
11056                let tab_size = settings.tab_size.get();
11057                let mut rows = selection.spanned_rows(false, &display_map);
11058
11059                // Avoid re-outdenting a row that has already been outdented by a
11060                // previous selection.
11061                if let Some(last_row) = last_outdent
11062                    && last_row == rows.start
11063                {
11064                    rows.start = rows.start.next_row();
11065                }
11066                let has_multiple_rows = rows.len() > 1;
11067                for row in rows.iter_rows() {
11068                    let indent_size = snapshot.indent_size_for_line(row);
11069                    if indent_size.len > 0 {
11070                        let deletion_len = match indent_size.kind {
11071                            IndentKind::Space => {
11072                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
11073                                if columns_to_prev_tab_stop == 0 {
11074                                    tab_size
11075                                } else {
11076                                    columns_to_prev_tab_stop
11077                                }
11078                            }
11079                            IndentKind::Tab => 1,
11080                        };
11081                        let start = if has_multiple_rows
11082                            || deletion_len > selection.start.column
11083                            || indent_size.len < selection.start.column
11084                        {
11085                            0
11086                        } else {
11087                            selection.start.column - deletion_len
11088                        };
11089                        deletion_ranges.push(
11090                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11091                        );
11092                        last_outdent = Some(row);
11093                    }
11094                }
11095            }
11096        }
11097
11098        self.transact(window, cx, |this, window, cx| {
11099            this.buffer.update(cx, |buffer, cx| {
11100                let empty_str: Arc<str> = Arc::default();
11101                buffer.edit(
11102                    deletion_ranges
11103                        .into_iter()
11104                        .map(|range| (range, empty_str.clone())),
11105                    None,
11106                    cx,
11107                );
11108            });
11109            let selections = this
11110                .selections
11111                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11112            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11113        });
11114    }
11115
11116    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11117        if self.read_only(cx) {
11118            return;
11119        }
11120        if self.mode.is_single_line() {
11121            cx.propagate();
11122            return;
11123        }
11124
11125        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11126        let selections = self
11127            .selections
11128            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11129            .into_iter()
11130            .map(|s| s.range());
11131
11132        self.transact(window, cx, |this, window, cx| {
11133            this.buffer.update(cx, |buffer, cx| {
11134                buffer.autoindent_ranges(selections, cx);
11135            });
11136            let selections = this
11137                .selections
11138                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11139            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11140        });
11141    }
11142
11143    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11145        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11146        let selections = self.selections.all::<Point>(&display_map);
11147
11148        let mut new_cursors = Vec::new();
11149        let mut edit_ranges = Vec::new();
11150        let mut selections = selections.iter().peekable();
11151        while let Some(selection) = selections.next() {
11152            let mut rows = selection.spanned_rows(false, &display_map);
11153
11154            // Accumulate contiguous regions of rows that we want to delete.
11155            while let Some(next_selection) = selections.peek() {
11156                let next_rows = next_selection.spanned_rows(false, &display_map);
11157                if next_rows.start <= rows.end {
11158                    rows.end = next_rows.end;
11159                    selections.next().unwrap();
11160                } else {
11161                    break;
11162                }
11163            }
11164
11165            let buffer = display_map.buffer_snapshot();
11166            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11167            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11168                // If there's a line after the range, delete the \n from the end of the row range
11169                (
11170                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11171                    rows.end,
11172                )
11173            } else {
11174                // If there isn't a line after the range, delete the \n from the line before the
11175                // start of the row range
11176                edit_start = edit_start.saturating_sub_usize(1);
11177                (buffer.len(), rows.start.previous_row())
11178            };
11179
11180            let text_layout_details = self.text_layout_details(window, cx);
11181            let x = display_map.x_for_display_point(
11182                selection.head().to_display_point(&display_map),
11183                &text_layout_details,
11184            );
11185            let row = Point::new(target_row.0, 0)
11186                .to_display_point(&display_map)
11187                .row();
11188            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11189
11190            new_cursors.push((
11191                selection.id,
11192                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11193                SelectionGoal::None,
11194            ));
11195            edit_ranges.push(edit_start..edit_end);
11196        }
11197
11198        self.transact(window, cx, |this, window, cx| {
11199            let buffer = this.buffer.update(cx, |buffer, cx| {
11200                let empty_str: Arc<str> = Arc::default();
11201                buffer.edit(
11202                    edit_ranges
11203                        .into_iter()
11204                        .map(|range| (range, empty_str.clone())),
11205                    None,
11206                    cx,
11207                );
11208                buffer.snapshot(cx)
11209            });
11210            let new_selections = new_cursors
11211                .into_iter()
11212                .map(|(id, cursor, goal)| {
11213                    let cursor = cursor.to_point(&buffer);
11214                    Selection {
11215                        id,
11216                        start: cursor,
11217                        end: cursor,
11218                        reversed: false,
11219                        goal,
11220                    }
11221                })
11222                .collect();
11223
11224            this.change_selections(Default::default(), window, cx, |s| {
11225                s.select(new_selections);
11226            });
11227        });
11228    }
11229
11230    pub fn join_lines_impl(
11231        &mut self,
11232        insert_whitespace: bool,
11233        window: &mut Window,
11234        cx: &mut Context<Self>,
11235    ) {
11236        if self.read_only(cx) {
11237            return;
11238        }
11239        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11240        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11241            let start = MultiBufferRow(selection.start.row);
11242            // Treat single line selections as if they include the next line. Otherwise this action
11243            // would do nothing for single line selections individual cursors.
11244            let end = if selection.start.row == selection.end.row {
11245                MultiBufferRow(selection.start.row + 1)
11246            } else {
11247                MultiBufferRow(selection.end.row)
11248            };
11249
11250            if let Some(last_row_range) = row_ranges.last_mut()
11251                && start <= last_row_range.end
11252            {
11253                last_row_range.end = end;
11254                continue;
11255            }
11256            row_ranges.push(start..end);
11257        }
11258
11259        let snapshot = self.buffer.read(cx).snapshot(cx);
11260        let mut cursor_positions = Vec::new();
11261        for row_range in &row_ranges {
11262            let anchor = snapshot.anchor_before(Point::new(
11263                row_range.end.previous_row().0,
11264                snapshot.line_len(row_range.end.previous_row()),
11265            ));
11266            cursor_positions.push(anchor..anchor);
11267        }
11268
11269        self.transact(window, cx, |this, window, cx| {
11270            for row_range in row_ranges.into_iter().rev() {
11271                for row in row_range.iter_rows().rev() {
11272                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11273                    let next_line_row = row.next_row();
11274                    let indent = snapshot.indent_size_for_line(next_line_row);
11275                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
11276
11277                    let replace =
11278                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11279                            " "
11280                        } else {
11281                            ""
11282                        };
11283
11284                    this.buffer.update(cx, |buffer, cx| {
11285                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11286                    });
11287                }
11288            }
11289
11290            this.change_selections(Default::default(), window, cx, |s| {
11291                s.select_anchor_ranges(cursor_positions)
11292            });
11293        });
11294    }
11295
11296    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11297        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11298        self.join_lines_impl(true, window, cx);
11299    }
11300
11301    pub fn sort_lines_case_sensitive(
11302        &mut self,
11303        _: &SortLinesCaseSensitive,
11304        window: &mut Window,
11305        cx: &mut Context<Self>,
11306    ) {
11307        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11308    }
11309
11310    pub fn sort_lines_by_length(
11311        &mut self,
11312        _: &SortLinesByLength,
11313        window: &mut Window,
11314        cx: &mut Context<Self>,
11315    ) {
11316        self.manipulate_immutable_lines(window, cx, |lines| {
11317            lines.sort_by_key(|&line| line.chars().count())
11318        })
11319    }
11320
11321    pub fn sort_lines_case_insensitive(
11322        &mut self,
11323        _: &SortLinesCaseInsensitive,
11324        window: &mut Window,
11325        cx: &mut Context<Self>,
11326    ) {
11327        self.manipulate_immutable_lines(window, cx, |lines| {
11328            lines.sort_by_key(|line| line.to_lowercase())
11329        })
11330    }
11331
11332    pub fn unique_lines_case_insensitive(
11333        &mut self,
11334        _: &UniqueLinesCaseInsensitive,
11335        window: &mut Window,
11336        cx: &mut Context<Self>,
11337    ) {
11338        self.manipulate_immutable_lines(window, cx, |lines| {
11339            let mut seen = HashSet::default();
11340            lines.retain(|line| seen.insert(line.to_lowercase()));
11341        })
11342    }
11343
11344    pub fn unique_lines_case_sensitive(
11345        &mut self,
11346        _: &UniqueLinesCaseSensitive,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.manipulate_immutable_lines(window, cx, |lines| {
11351            let mut seen = HashSet::default();
11352            lines.retain(|line| seen.insert(*line));
11353        })
11354    }
11355
11356    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11357        let snapshot = self.buffer.read(cx).snapshot(cx);
11358        for selection in self.selections.disjoint_anchors_arc().iter() {
11359            if snapshot
11360                .language_at(selection.start)
11361                .and_then(|lang| lang.config().wrap_characters.as_ref())
11362                .is_some()
11363            {
11364                return true;
11365            }
11366        }
11367        false
11368    }
11369
11370    fn wrap_selections_in_tag(
11371        &mut self,
11372        _: &WrapSelectionsInTag,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11377
11378        let snapshot = self.buffer.read(cx).snapshot(cx);
11379
11380        let mut edits = Vec::new();
11381        let mut boundaries = Vec::new();
11382
11383        for selection in self
11384            .selections
11385            .all_adjusted(&self.display_snapshot(cx))
11386            .iter()
11387        {
11388            let Some(wrap_config) = snapshot
11389                .language_at(selection.start)
11390                .and_then(|lang| lang.config().wrap_characters.clone())
11391            else {
11392                continue;
11393            };
11394
11395            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11396            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11397
11398            let start_before = snapshot.anchor_before(selection.start);
11399            let end_after = snapshot.anchor_after(selection.end);
11400
11401            edits.push((start_before..start_before, open_tag));
11402            edits.push((end_after..end_after, close_tag));
11403
11404            boundaries.push((
11405                start_before,
11406                end_after,
11407                wrap_config.start_prefix.len(),
11408                wrap_config.end_suffix.len(),
11409            ));
11410        }
11411
11412        if edits.is_empty() {
11413            return;
11414        }
11415
11416        self.transact(window, cx, |this, window, cx| {
11417            let buffer = this.buffer.update(cx, |buffer, cx| {
11418                buffer.edit(edits, None, cx);
11419                buffer.snapshot(cx)
11420            });
11421
11422            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11423            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11424                boundaries.into_iter()
11425            {
11426                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11427                let close_offset = end_after
11428                    .to_offset(&buffer)
11429                    .saturating_sub_usize(end_suffix_len);
11430                new_selections.push(open_offset..open_offset);
11431                new_selections.push(close_offset..close_offset);
11432            }
11433
11434            this.change_selections(Default::default(), window, cx, |s| {
11435                s.select_ranges(new_selections);
11436            });
11437
11438            this.request_autoscroll(Autoscroll::fit(), cx);
11439        });
11440    }
11441
11442    pub fn toggle_read_only(
11443        &mut self,
11444        _: &workspace::ToggleReadOnlyFile,
11445        _: &mut Window,
11446        cx: &mut Context<Self>,
11447    ) {
11448        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11449            buffer.update(cx, |buffer, cx| {
11450                buffer.set_capability(
11451                    match buffer.capability() {
11452                        Capability::ReadWrite => Capability::Read,
11453                        Capability::Read => Capability::ReadWrite,
11454                        Capability::ReadOnly => Capability::ReadOnly,
11455                    },
11456                    cx,
11457                );
11458            })
11459        }
11460    }
11461
11462    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11463        let Some(project) = self.project.clone() else {
11464            return;
11465        };
11466        self.reload(project, window, cx)
11467            .detach_and_notify_err(window, cx);
11468    }
11469
11470    pub fn restore_file(
11471        &mut self,
11472        _: &::git::RestoreFile,
11473        window: &mut Window,
11474        cx: &mut Context<Self>,
11475    ) {
11476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11477        let mut buffer_ids = HashSet::default();
11478        let snapshot = self.buffer().read(cx).snapshot(cx);
11479        for selection in self
11480            .selections
11481            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11482        {
11483            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11484        }
11485
11486        let buffer = self.buffer().read(cx);
11487        let ranges = buffer_ids
11488            .into_iter()
11489            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11490            .collect::<Vec<_>>();
11491
11492        self.restore_hunks_in_ranges(ranges, window, cx);
11493    }
11494
11495    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11497        let selections = self
11498            .selections
11499            .all(&self.display_snapshot(cx))
11500            .into_iter()
11501            .map(|s| s.range())
11502            .collect();
11503        self.restore_hunks_in_ranges(selections, window, cx);
11504    }
11505
11506    pub fn restore_hunks_in_ranges(
11507        &mut self,
11508        ranges: Vec<Range<Point>>,
11509        window: &mut Window,
11510        cx: &mut Context<Editor>,
11511    ) {
11512        if self.delegate_stage_and_restore {
11513            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11514            if !hunks.is_empty() {
11515                cx.emit(EditorEvent::RestoreRequested { hunks });
11516            }
11517            return;
11518        }
11519        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11520        self.transact(window, cx, |editor, window, cx| {
11521            editor.restore_diff_hunks(hunks, cx);
11522            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
11523                selections.refresh()
11524            });
11525        });
11526    }
11527
11528    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11529        let mut revert_changes = HashMap::default();
11530        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11531        for (buffer_id, hunks) in &chunk_by {
11532            let hunks = hunks.collect::<Vec<_>>();
11533            for hunk in &hunks {
11534                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11535            }
11536            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11537        }
11538        if !revert_changes.is_empty() {
11539            self.buffer().update(cx, |multi_buffer, cx| {
11540                for (buffer_id, changes) in revert_changes {
11541                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11542                        buffer.update(cx, |buffer, cx| {
11543                            buffer.edit(
11544                                changes
11545                                    .into_iter()
11546                                    .map(|(range, text)| (range, text.to_string())),
11547                                None,
11548                                cx,
11549                            );
11550                        });
11551                    }
11552                }
11553            });
11554        }
11555    }
11556
11557    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11558        if let Some(status) = self
11559            .addons
11560            .iter()
11561            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11562        {
11563            return Some(status);
11564        }
11565        self.project
11566            .as_ref()?
11567            .read(cx)
11568            .status_for_buffer_id(buffer_id, cx)
11569    }
11570
11571    pub fn open_active_item_in_terminal(
11572        &mut self,
11573        _: &OpenInTerminal,
11574        window: &mut Window,
11575        cx: &mut Context<Self>,
11576    ) {
11577        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11578            let project_path = buffer.read(cx).project_path(cx)?;
11579            let project = self.project()?.read(cx);
11580            let entry = project.entry_for_path(&project_path, cx)?;
11581            let parent = match &entry.canonical_path {
11582                Some(canonical_path) => canonical_path.to_path_buf(),
11583                None => project.absolute_path(&project_path, cx)?,
11584            }
11585            .parent()?
11586            .to_path_buf();
11587            Some(parent)
11588        }) {
11589            window.dispatch_action(
11590                OpenTerminal {
11591                    working_directory,
11592                    local: false,
11593                }
11594                .boxed_clone(),
11595                cx,
11596            );
11597        }
11598    }
11599
11600    fn set_breakpoint_context_menu(
11601        &mut self,
11602        display_row: DisplayRow,
11603        position: Option<Anchor>,
11604        clicked_point: gpui::Point<Pixels>,
11605        window: &mut Window,
11606        cx: &mut Context<Self>,
11607    ) {
11608        let source = self
11609            .buffer
11610            .read(cx)
11611            .snapshot(cx)
11612            .anchor_before(Point::new(display_row.0, 0u32));
11613
11614        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11615
11616        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11617            self,
11618            source,
11619            clicked_point,
11620            context_menu,
11621            window,
11622            cx,
11623        );
11624    }
11625
11626    fn add_edit_breakpoint_block(
11627        &mut self,
11628        anchor: Anchor,
11629        breakpoint: &Breakpoint,
11630        edit_action: BreakpointPromptEditAction,
11631        window: &mut Window,
11632        cx: &mut Context<Self>,
11633    ) {
11634        let weak_editor = cx.weak_entity();
11635        let bp_prompt = cx.new(|cx| {
11636            BreakpointPromptEditor::new(
11637                weak_editor,
11638                anchor,
11639                breakpoint.clone(),
11640                edit_action,
11641                window,
11642                cx,
11643            )
11644        });
11645
11646        let height = bp_prompt.update(cx, |this, cx| {
11647            this.prompt
11648                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11649        });
11650        let cloned_prompt = bp_prompt.clone();
11651        let blocks = vec![BlockProperties {
11652            style: BlockStyle::Sticky,
11653            placement: BlockPlacement::Above(anchor),
11654            height: Some(height),
11655            render: Arc::new(move |cx| {
11656                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11657                cloned_prompt.clone().into_any_element()
11658            }),
11659            priority: 0,
11660        }];
11661
11662        let focus_handle = bp_prompt.focus_handle(cx);
11663        window.focus(&focus_handle, cx);
11664
11665        let block_ids = self.insert_blocks(blocks, None, cx);
11666        bp_prompt.update(cx, |prompt, _| {
11667            prompt.add_block_ids(block_ids);
11668        });
11669    }
11670
11671    pub(crate) fn breakpoint_at_row(
11672        &self,
11673        row: u32,
11674        window: &mut Window,
11675        cx: &mut Context<Self>,
11676    ) -> Option<(Anchor, Breakpoint)> {
11677        let snapshot = self.snapshot(window, cx);
11678        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11679
11680        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11681    }
11682
11683    pub(crate) fn breakpoint_at_anchor(
11684        &self,
11685        breakpoint_position: Anchor,
11686        snapshot: &EditorSnapshot,
11687        cx: &mut Context<Self>,
11688    ) -> Option<(Anchor, Breakpoint)> {
11689        let buffer = self
11690            .buffer
11691            .read(cx)
11692            .buffer_for_anchor(breakpoint_position, cx)?;
11693
11694        let enclosing_excerpt = breakpoint_position.excerpt_id;
11695        let buffer_snapshot = buffer.read(cx).snapshot();
11696
11697        let row = buffer_snapshot
11698            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11699            .row;
11700
11701        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11702        let anchor_end = snapshot
11703            .buffer_snapshot()
11704            .anchor_after(Point::new(row, line_len));
11705
11706        self.breakpoint_store
11707            .as_ref()?
11708            .read_with(cx, |breakpoint_store, cx| {
11709                breakpoint_store
11710                    .breakpoints(
11711                        &buffer,
11712                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11713                        &buffer_snapshot,
11714                        cx,
11715                    )
11716                    .next()
11717                    .and_then(|(bp, _)| {
11718                        let breakpoint_row = buffer_snapshot
11719                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11720                            .row;
11721
11722                        if breakpoint_row == row {
11723                            snapshot
11724                                .buffer_snapshot()
11725                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11726                                .map(|position| (position, bp.bp.clone()))
11727                        } else {
11728                            None
11729                        }
11730                    })
11731            })
11732    }
11733
11734    pub fn edit_log_breakpoint(
11735        &mut self,
11736        _: &EditLogBreakpoint,
11737        window: &mut Window,
11738        cx: &mut Context<Self>,
11739    ) {
11740        if self.breakpoint_store.is_none() {
11741            return;
11742        }
11743
11744        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11745            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11746                message: None,
11747                state: BreakpointState::Enabled,
11748                condition: None,
11749                hit_condition: None,
11750            });
11751
11752            self.add_edit_breakpoint_block(
11753                anchor,
11754                &breakpoint,
11755                BreakpointPromptEditAction::Log,
11756                window,
11757                cx,
11758            );
11759        }
11760    }
11761
11762    fn breakpoints_at_cursors(
11763        &self,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11767        let snapshot = self.snapshot(window, cx);
11768        let cursors = self
11769            .selections
11770            .disjoint_anchors_arc()
11771            .iter()
11772            .map(|selection| {
11773                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11774
11775                let breakpoint_position = self
11776                    .breakpoint_at_row(cursor_position.row, window, cx)
11777                    .map(|bp| bp.0)
11778                    .unwrap_or_else(|| {
11779                        snapshot
11780                            .display_snapshot
11781                            .buffer_snapshot()
11782                            .anchor_after(Point::new(cursor_position.row, 0))
11783                    });
11784
11785                let breakpoint = self
11786                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11787                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11788
11789                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11790            })
11791            // 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.
11792            .collect::<HashMap<Anchor, _>>();
11793
11794        cursors.into_iter().collect()
11795    }
11796
11797    pub fn enable_breakpoint(
11798        &mut self,
11799        _: &crate::actions::EnableBreakpoint,
11800        window: &mut Window,
11801        cx: &mut Context<Self>,
11802    ) {
11803        if self.breakpoint_store.is_none() {
11804            return;
11805        }
11806
11807        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11808            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11809                continue;
11810            };
11811            self.edit_breakpoint_at_anchor(
11812                anchor,
11813                breakpoint,
11814                BreakpointEditAction::InvertState,
11815                cx,
11816            );
11817        }
11818    }
11819
11820    pub fn disable_breakpoint(
11821        &mut self,
11822        _: &crate::actions::DisableBreakpoint,
11823        window: &mut Window,
11824        cx: &mut Context<Self>,
11825    ) {
11826        if self.breakpoint_store.is_none() {
11827            return;
11828        }
11829
11830        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11831            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11832                continue;
11833            };
11834            self.edit_breakpoint_at_anchor(
11835                anchor,
11836                breakpoint,
11837                BreakpointEditAction::InvertState,
11838                cx,
11839            );
11840        }
11841    }
11842
11843    pub fn toggle_breakpoint(
11844        &mut self,
11845        _: &crate::actions::ToggleBreakpoint,
11846        window: &mut Window,
11847        cx: &mut Context<Self>,
11848    ) {
11849        if self.breakpoint_store.is_none() {
11850            return;
11851        }
11852
11853        let snapshot = self.snapshot(window, cx);
11854        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11855            if self.gutter_breakpoint_indicator.0.is_some() {
11856                let display_row = anchor
11857                    .to_point(snapshot.buffer_snapshot())
11858                    .to_display_point(&snapshot.display_snapshot)
11859                    .row();
11860                self.update_breakpoint_collision_on_toggle(
11861                    display_row,
11862                    &BreakpointEditAction::Toggle,
11863                );
11864            }
11865
11866            if let Some(breakpoint) = breakpoint {
11867                self.edit_breakpoint_at_anchor(
11868                    anchor,
11869                    breakpoint,
11870                    BreakpointEditAction::Toggle,
11871                    cx,
11872                );
11873            } else {
11874                self.edit_breakpoint_at_anchor(
11875                    anchor,
11876                    Breakpoint::new_standard(),
11877                    BreakpointEditAction::Toggle,
11878                    cx,
11879                );
11880            }
11881        }
11882    }
11883
11884    fn update_breakpoint_collision_on_toggle(
11885        &mut self,
11886        display_row: DisplayRow,
11887        edit_action: &BreakpointEditAction,
11888    ) {
11889        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
11890            if breakpoint_indicator.display_row == display_row
11891                && matches!(edit_action, BreakpointEditAction::Toggle)
11892            {
11893                breakpoint_indicator.collides_with_existing_breakpoint =
11894                    !breakpoint_indicator.collides_with_existing_breakpoint;
11895            }
11896        }
11897    }
11898
11899    pub fn edit_breakpoint_at_anchor(
11900        &mut self,
11901        breakpoint_position: Anchor,
11902        breakpoint: Breakpoint,
11903        edit_action: BreakpointEditAction,
11904        cx: &mut Context<Self>,
11905    ) {
11906        let Some(breakpoint_store) = &self.breakpoint_store else {
11907            return;
11908        };
11909
11910        let Some(buffer) = self
11911            .buffer
11912            .read(cx)
11913            .buffer_for_anchor(breakpoint_position, cx)
11914        else {
11915            return;
11916        };
11917
11918        breakpoint_store.update(cx, |breakpoint_store, cx| {
11919            breakpoint_store.toggle_breakpoint(
11920                buffer,
11921                BreakpointWithPosition {
11922                    position: breakpoint_position.text_anchor,
11923                    bp: breakpoint,
11924                },
11925                edit_action,
11926                cx,
11927            );
11928        });
11929
11930        cx.notify();
11931    }
11932
11933    #[cfg(any(test, feature = "test-support"))]
11934    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11935        self.breakpoint_store.clone()
11936    }
11937
11938    pub fn prepare_restore_change(
11939        &self,
11940        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11941        hunk: &MultiBufferDiffHunk,
11942        cx: &mut App,
11943    ) -> Option<()> {
11944        if hunk.is_created_file() {
11945            return None;
11946        }
11947        let buffer = self.buffer.read(cx);
11948        let diff = buffer.diff_for(hunk.buffer_id)?;
11949        let buffer = buffer.buffer(hunk.buffer_id)?;
11950        let buffer = buffer.read(cx);
11951        let original_text = diff
11952            .read(cx)
11953            .base_text(cx)
11954            .as_rope()
11955            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11956        let buffer_snapshot = buffer.snapshot();
11957        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11958        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11959            probe
11960                .0
11961                .start
11962                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11963                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11964        }) {
11965            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11966            Some(())
11967        } else {
11968            None
11969        }
11970    }
11971
11972    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11973        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11974    }
11975
11976    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11977        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11978    }
11979
11980    pub fn rotate_selections_forward(
11981        &mut self,
11982        _: &RotateSelectionsForward,
11983        window: &mut Window,
11984        cx: &mut Context<Self>,
11985    ) {
11986        self.rotate_selections(window, cx, false)
11987    }
11988
11989    pub fn rotate_selections_backward(
11990        &mut self,
11991        _: &RotateSelectionsBackward,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        self.rotate_selections(window, cx, true)
11996    }
11997
11998    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12000        let display_snapshot = self.display_snapshot(cx);
12001        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12002
12003        if selections.len() < 2 {
12004            return;
12005        }
12006
12007        let (edits, new_selections) = {
12008            let buffer = self.buffer.read(cx).read(cx);
12009            let has_selections = selections.iter().any(|s| !s.is_empty());
12010            if has_selections {
12011                let mut selected_texts: Vec<String> = selections
12012                    .iter()
12013                    .map(|selection| {
12014                        buffer
12015                            .text_for_range(selection.start..selection.end)
12016                            .collect()
12017                    })
12018                    .collect();
12019
12020                if reverse {
12021                    selected_texts.rotate_left(1);
12022                } else {
12023                    selected_texts.rotate_right(1);
12024                }
12025
12026                let mut offset_delta: i64 = 0;
12027                let mut new_selections = Vec::new();
12028                let edits: Vec<_> = selections
12029                    .iter()
12030                    .zip(selected_texts.iter())
12031                    .map(|(selection, new_text)| {
12032                        let old_len = (selection.end.0 - selection.start.0) as i64;
12033                        let new_len = new_text.len() as i64;
12034                        let adjusted_start =
12035                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12036                        let adjusted_end =
12037                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12038
12039                        new_selections.push(Selection {
12040                            id: selection.id,
12041                            start: adjusted_start,
12042                            end: adjusted_end,
12043                            reversed: selection.reversed,
12044                            goal: selection.goal,
12045                        });
12046
12047                        offset_delta += new_len - old_len;
12048                        (selection.start..selection.end, new_text.clone())
12049                    })
12050                    .collect();
12051                (edits, new_selections)
12052            } else {
12053                let mut all_rows: Vec<u32> = selections
12054                    .iter()
12055                    .map(|selection| buffer.offset_to_point(selection.start).row)
12056                    .collect();
12057                all_rows.sort_unstable();
12058                all_rows.dedup();
12059
12060                if all_rows.len() < 2 {
12061                    return;
12062                }
12063
12064                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12065                    .iter()
12066                    .map(|&row| {
12067                        let start = Point::new(row, 0);
12068                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12069                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12070                    })
12071                    .collect();
12072
12073                let mut line_texts: Vec<String> = line_ranges
12074                    .iter()
12075                    .map(|range| buffer.text_for_range(range.clone()).collect())
12076                    .collect();
12077
12078                if reverse {
12079                    line_texts.rotate_left(1);
12080                } else {
12081                    line_texts.rotate_right(1);
12082                }
12083
12084                let edits = line_ranges
12085                    .iter()
12086                    .zip(line_texts.iter())
12087                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12088                    .collect();
12089
12090                let num_rows = all_rows.len();
12091                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12092                    .iter()
12093                    .enumerate()
12094                    .map(|(i, &row)| (row, i))
12095                    .collect();
12096
12097                // Compute new line start offsets after rotation (handles CRLF)
12098                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12099                let first_line_start = line_ranges[0].start.0;
12100                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12101                for text in line_texts.iter().take(num_rows - 1) {
12102                    let prev_start = *new_line_starts.last().unwrap();
12103                    new_line_starts.push(prev_start + text.len() + newline_len);
12104                }
12105
12106                let new_selections = selections
12107                    .iter()
12108                    .map(|selection| {
12109                        let point = buffer.offset_to_point(selection.start);
12110                        let old_index = row_to_index[&point.row];
12111                        let new_index = if reverse {
12112                            (old_index + num_rows - 1) % num_rows
12113                        } else {
12114                            (old_index + 1) % num_rows
12115                        };
12116                        let new_offset =
12117                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12118                        Selection {
12119                            id: selection.id,
12120                            start: new_offset,
12121                            end: new_offset,
12122                            reversed: selection.reversed,
12123                            goal: selection.goal,
12124                        }
12125                    })
12126                    .collect();
12127
12128                (edits, new_selections)
12129            }
12130        };
12131
12132        self.transact(window, cx, |this, window, cx| {
12133            this.buffer.update(cx, |buffer, cx| {
12134                buffer.edit(edits, None, cx);
12135            });
12136            this.change_selections(Default::default(), window, cx, |s| {
12137                s.select(new_selections);
12138            });
12139        });
12140    }
12141
12142    fn manipulate_lines<M>(
12143        &mut self,
12144        window: &mut Window,
12145        cx: &mut Context<Self>,
12146        mut manipulate: M,
12147    ) where
12148        M: FnMut(&str) -> LineManipulationResult,
12149    {
12150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12151
12152        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12153        let buffer = self.buffer.read(cx).snapshot(cx);
12154
12155        let mut edits = Vec::new();
12156
12157        let selections = self.selections.all::<Point>(&display_map);
12158        let mut selections = selections.iter().peekable();
12159        let mut contiguous_row_selections = Vec::new();
12160        let mut new_selections = Vec::new();
12161        let mut added_lines = 0;
12162        let mut removed_lines = 0;
12163
12164        while let Some(selection) = selections.next() {
12165            let (start_row, end_row) = consume_contiguous_rows(
12166                &mut contiguous_row_selections,
12167                selection,
12168                &display_map,
12169                &mut selections,
12170            );
12171
12172            let start_point = Point::new(start_row.0, 0);
12173            let end_point = Point::new(
12174                end_row.previous_row().0,
12175                buffer.line_len(end_row.previous_row()),
12176            );
12177            let text = buffer
12178                .text_for_range(start_point..end_point)
12179                .collect::<String>();
12180
12181            let LineManipulationResult {
12182                new_text,
12183                line_count_before,
12184                line_count_after,
12185            } = manipulate(&text);
12186
12187            edits.push((start_point..end_point, new_text));
12188
12189            // Selections must change based on added and removed line count
12190            let start_row =
12191                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12192            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12193            new_selections.push(Selection {
12194                id: selection.id,
12195                start: start_row,
12196                end: end_row,
12197                goal: SelectionGoal::None,
12198                reversed: selection.reversed,
12199            });
12200
12201            if line_count_after > line_count_before {
12202                added_lines += line_count_after - line_count_before;
12203            } else if line_count_before > line_count_after {
12204                removed_lines += line_count_before - line_count_after;
12205            }
12206        }
12207
12208        self.transact(window, cx, |this, window, cx| {
12209            let buffer = this.buffer.update(cx, |buffer, cx| {
12210                buffer.edit(edits, None, cx);
12211                buffer.snapshot(cx)
12212            });
12213
12214            // Recalculate offsets on newly edited buffer
12215            let new_selections = new_selections
12216                .iter()
12217                .map(|s| {
12218                    let start_point = Point::new(s.start.0, 0);
12219                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12220                    Selection {
12221                        id: s.id,
12222                        start: buffer.point_to_offset(start_point),
12223                        end: buffer.point_to_offset(end_point),
12224                        goal: s.goal,
12225                        reversed: s.reversed,
12226                    }
12227                })
12228                .collect();
12229
12230            this.change_selections(Default::default(), window, cx, |s| {
12231                s.select(new_selections);
12232            });
12233
12234            this.request_autoscroll(Autoscroll::fit(), cx);
12235        });
12236    }
12237
12238    fn manipulate_immutable_lines<Fn>(
12239        &mut self,
12240        window: &mut Window,
12241        cx: &mut Context<Self>,
12242        mut callback: Fn,
12243    ) where
12244        Fn: FnMut(&mut Vec<&str>),
12245    {
12246        self.manipulate_lines(window, cx, |text| {
12247            let mut lines: Vec<&str> = text.split('\n').collect();
12248            let line_count_before = lines.len();
12249
12250            callback(&mut lines);
12251
12252            LineManipulationResult {
12253                new_text: lines.join("\n"),
12254                line_count_before,
12255                line_count_after: lines.len(),
12256            }
12257        });
12258    }
12259
12260    fn manipulate_mutable_lines<Fn>(
12261        &mut self,
12262        window: &mut Window,
12263        cx: &mut Context<Self>,
12264        mut callback: Fn,
12265    ) where
12266        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12267    {
12268        self.manipulate_lines(window, cx, |text| {
12269            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12270            let line_count_before = lines.len();
12271
12272            callback(&mut lines);
12273
12274            LineManipulationResult {
12275                new_text: lines.join("\n"),
12276                line_count_before,
12277                line_count_after: lines.len(),
12278            }
12279        });
12280    }
12281
12282    pub fn convert_indentation_to_spaces(
12283        &mut self,
12284        _: &ConvertIndentationToSpaces,
12285        window: &mut Window,
12286        cx: &mut Context<Self>,
12287    ) {
12288        let settings = self.buffer.read(cx).language_settings(cx);
12289        let tab_size = settings.tab_size.get() as usize;
12290
12291        self.manipulate_mutable_lines(window, cx, |lines| {
12292            // Allocates a reasonably sized scratch buffer once for the whole loop
12293            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12294            // Avoids recomputing spaces that could be inserted many times
12295            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12296                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12297                .collect();
12298
12299            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12300                let mut chars = line.as_ref().chars();
12301                let mut col = 0;
12302                let mut changed = false;
12303
12304                for ch in chars.by_ref() {
12305                    match ch {
12306                        ' ' => {
12307                            reindented_line.push(' ');
12308                            col += 1;
12309                        }
12310                        '\t' => {
12311                            // \t are converted to spaces depending on the current column
12312                            let spaces_len = tab_size - (col % tab_size);
12313                            reindented_line.extend(&space_cache[spaces_len - 1]);
12314                            col += spaces_len;
12315                            changed = true;
12316                        }
12317                        _ => {
12318                            // If we dont append before break, the character is consumed
12319                            reindented_line.push(ch);
12320                            break;
12321                        }
12322                    }
12323                }
12324
12325                if !changed {
12326                    reindented_line.clear();
12327                    continue;
12328                }
12329                // Append the rest of the line and replace old reference with new one
12330                reindented_line.extend(chars);
12331                *line = Cow::Owned(reindented_line.clone());
12332                reindented_line.clear();
12333            }
12334        });
12335    }
12336
12337    pub fn convert_indentation_to_tabs(
12338        &mut self,
12339        _: &ConvertIndentationToTabs,
12340        window: &mut Window,
12341        cx: &mut Context<Self>,
12342    ) {
12343        let settings = self.buffer.read(cx).language_settings(cx);
12344        let tab_size = settings.tab_size.get() as usize;
12345
12346        self.manipulate_mutable_lines(window, cx, |lines| {
12347            // Allocates a reasonably sized buffer once for the whole loop
12348            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12349            // Avoids recomputing spaces that could be inserted many times
12350            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12351                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12352                .collect();
12353
12354            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12355                let mut chars = line.chars();
12356                let mut spaces_count = 0;
12357                let mut first_non_indent_char = None;
12358                let mut changed = false;
12359
12360                for ch in chars.by_ref() {
12361                    match ch {
12362                        ' ' => {
12363                            // Keep track of spaces. Append \t when we reach tab_size
12364                            spaces_count += 1;
12365                            changed = true;
12366                            if spaces_count == tab_size {
12367                                reindented_line.push('\t');
12368                                spaces_count = 0;
12369                            }
12370                        }
12371                        '\t' => {
12372                            reindented_line.push('\t');
12373                            spaces_count = 0;
12374                        }
12375                        _ => {
12376                            // Dont append it yet, we might have remaining spaces
12377                            first_non_indent_char = Some(ch);
12378                            break;
12379                        }
12380                    }
12381                }
12382
12383                if !changed {
12384                    reindented_line.clear();
12385                    continue;
12386                }
12387                // Remaining spaces that didn't make a full tab stop
12388                if spaces_count > 0 {
12389                    reindented_line.extend(&space_cache[spaces_count - 1]);
12390                }
12391                // If we consume an extra character that was not indentation, add it back
12392                if let Some(extra_char) = first_non_indent_char {
12393                    reindented_line.push(extra_char);
12394                }
12395                // Append the rest of the line and replace old reference with new one
12396                reindented_line.extend(chars);
12397                *line = Cow::Owned(reindented_line.clone());
12398                reindented_line.clear();
12399            }
12400        });
12401    }
12402
12403    pub fn convert_to_upper_case(
12404        &mut self,
12405        _: &ConvertToUpperCase,
12406        window: &mut Window,
12407        cx: &mut Context<Self>,
12408    ) {
12409        self.manipulate_text(window, cx, |text| text.to_uppercase())
12410    }
12411
12412    pub fn convert_to_lower_case(
12413        &mut self,
12414        _: &ConvertToLowerCase,
12415        window: &mut Window,
12416        cx: &mut Context<Self>,
12417    ) {
12418        self.manipulate_text(window, cx, |text| text.to_lowercase())
12419    }
12420
12421    pub fn convert_to_title_case(
12422        &mut self,
12423        _: &ConvertToTitleCase,
12424        window: &mut Window,
12425        cx: &mut Context<Self>,
12426    ) {
12427        self.manipulate_text(window, cx, |text| {
12428            text.split('\n')
12429                .map(|line| line.to_case(Case::Title))
12430                .join("\n")
12431        })
12432    }
12433
12434    pub fn convert_to_snake_case(
12435        &mut self,
12436        _: &ConvertToSnakeCase,
12437        window: &mut Window,
12438        cx: &mut Context<Self>,
12439    ) {
12440        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12441    }
12442
12443    pub fn convert_to_kebab_case(
12444        &mut self,
12445        _: &ConvertToKebabCase,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12450    }
12451
12452    pub fn convert_to_upper_camel_case(
12453        &mut self,
12454        _: &ConvertToUpperCamelCase,
12455        window: &mut Window,
12456        cx: &mut Context<Self>,
12457    ) {
12458        self.manipulate_text(window, cx, |text| {
12459            text.split('\n')
12460                .map(|line| line.to_case(Case::UpperCamel))
12461                .join("\n")
12462        })
12463    }
12464
12465    pub fn convert_to_lower_camel_case(
12466        &mut self,
12467        _: &ConvertToLowerCamelCase,
12468        window: &mut Window,
12469        cx: &mut Context<Self>,
12470    ) {
12471        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12472    }
12473
12474    pub fn convert_to_opposite_case(
12475        &mut self,
12476        _: &ConvertToOppositeCase,
12477        window: &mut Window,
12478        cx: &mut Context<Self>,
12479    ) {
12480        self.manipulate_text(window, cx, |text| {
12481            text.chars()
12482                .fold(String::with_capacity(text.len()), |mut t, c| {
12483                    if c.is_uppercase() {
12484                        t.extend(c.to_lowercase());
12485                    } else {
12486                        t.extend(c.to_uppercase());
12487                    }
12488                    t
12489                })
12490        })
12491    }
12492
12493    pub fn convert_to_sentence_case(
12494        &mut self,
12495        _: &ConvertToSentenceCase,
12496        window: &mut Window,
12497        cx: &mut Context<Self>,
12498    ) {
12499        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12500    }
12501
12502    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12503        self.manipulate_text(window, cx, |text| {
12504            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12505            if has_upper_case_characters {
12506                text.to_lowercase()
12507            } else {
12508                text.to_uppercase()
12509            }
12510        })
12511    }
12512
12513    pub fn convert_to_rot13(
12514        &mut self,
12515        _: &ConvertToRot13,
12516        window: &mut Window,
12517        cx: &mut Context<Self>,
12518    ) {
12519        self.manipulate_text(window, cx, |text| {
12520            text.chars()
12521                .map(|c| match c {
12522                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12523                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12524                    _ => c,
12525                })
12526                .collect()
12527        })
12528    }
12529
12530    pub fn convert_to_rot47(
12531        &mut self,
12532        _: &ConvertToRot47,
12533        window: &mut Window,
12534        cx: &mut Context<Self>,
12535    ) {
12536        self.manipulate_text(window, cx, |text| {
12537            text.chars()
12538                .map(|c| {
12539                    let code_point = c as u32;
12540                    if code_point >= 33 && code_point <= 126 {
12541                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12542                    }
12543                    c
12544                })
12545                .collect()
12546        })
12547    }
12548
12549    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12550    where
12551        Fn: FnMut(&str) -> String,
12552    {
12553        let buffer = self.buffer.read(cx).snapshot(cx);
12554
12555        let mut new_selections = Vec::new();
12556        let mut edits = Vec::new();
12557        let mut selection_adjustment = 0isize;
12558
12559        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12560            let selection_is_empty = selection.is_empty();
12561
12562            let (start, end) = if selection_is_empty {
12563                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12564                (word_range.start, word_range.end)
12565            } else {
12566                (
12567                    buffer.point_to_offset(selection.start),
12568                    buffer.point_to_offset(selection.end),
12569                )
12570            };
12571
12572            let text = buffer.text_for_range(start..end).collect::<String>();
12573            let old_length = text.len() as isize;
12574            let text = callback(&text);
12575
12576            new_selections.push(Selection {
12577                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12578                end: MultiBufferOffset(
12579                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12580                ),
12581                goal: SelectionGoal::None,
12582                id: selection.id,
12583                reversed: selection.reversed,
12584            });
12585
12586            selection_adjustment += old_length - text.len() as isize;
12587
12588            edits.push((start..end, text));
12589        }
12590
12591        self.transact(window, cx, |this, window, cx| {
12592            this.buffer.update(cx, |buffer, cx| {
12593                buffer.edit(edits, None, cx);
12594            });
12595
12596            this.change_selections(Default::default(), window, cx, |s| {
12597                s.select(new_selections);
12598            });
12599
12600            this.request_autoscroll(Autoscroll::fit(), cx);
12601        });
12602    }
12603
12604    pub fn move_selection_on_drop(
12605        &mut self,
12606        selection: &Selection<Anchor>,
12607        target: DisplayPoint,
12608        is_cut: bool,
12609        window: &mut Window,
12610        cx: &mut Context<Self>,
12611    ) {
12612        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12613        let buffer = display_map.buffer_snapshot();
12614        let mut edits = Vec::new();
12615        let insert_point = display_map
12616            .clip_point(target, Bias::Left)
12617            .to_point(&display_map);
12618        let text = buffer
12619            .text_for_range(selection.start..selection.end)
12620            .collect::<String>();
12621        if is_cut {
12622            edits.push(((selection.start..selection.end), String::new()));
12623        }
12624        let insert_anchor = buffer.anchor_before(insert_point);
12625        edits.push(((insert_anchor..insert_anchor), text));
12626        let last_edit_start = insert_anchor.bias_left(buffer);
12627        let last_edit_end = insert_anchor.bias_right(buffer);
12628        self.transact(window, cx, |this, window, cx| {
12629            this.buffer.update(cx, |buffer, cx| {
12630                buffer.edit(edits, None, cx);
12631            });
12632            this.change_selections(Default::default(), window, cx, |s| {
12633                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12634            });
12635        });
12636    }
12637
12638    pub fn clear_selection_drag_state(&mut self) {
12639        self.selection_drag_state = SelectionDragState::None;
12640    }
12641
12642    pub fn duplicate(
12643        &mut self,
12644        upwards: bool,
12645        whole_lines: bool,
12646        window: &mut Window,
12647        cx: &mut Context<Self>,
12648    ) {
12649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12650
12651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12652        let buffer = display_map.buffer_snapshot();
12653        let selections = self.selections.all::<Point>(&display_map);
12654
12655        let mut edits = Vec::new();
12656        let mut selections_iter = selections.iter().peekable();
12657        while let Some(selection) = selections_iter.next() {
12658            let mut rows = selection.spanned_rows(false, &display_map);
12659            // duplicate line-wise
12660            if whole_lines || selection.start == selection.end {
12661                // Avoid duplicating the same lines twice.
12662                while let Some(next_selection) = selections_iter.peek() {
12663                    let next_rows = next_selection.spanned_rows(false, &display_map);
12664                    if next_rows.start < rows.end {
12665                        rows.end = next_rows.end;
12666                        selections_iter.next().unwrap();
12667                    } else {
12668                        break;
12669                    }
12670                }
12671
12672                // Copy the text from the selected row region and splice it either at the start
12673                // or end of the region.
12674                let start = Point::new(rows.start.0, 0);
12675                let end = Point::new(
12676                    rows.end.previous_row().0,
12677                    buffer.line_len(rows.end.previous_row()),
12678                );
12679
12680                let mut text = buffer.text_for_range(start..end).collect::<String>();
12681
12682                let insert_location = if upwards {
12683                    // When duplicating upward, we need to insert before the current line.
12684                    // If we're on the last line and it doesn't end with a newline,
12685                    // we need to add a newline before the duplicated content.
12686                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12687                        && buffer.max_point().column > 0
12688                        && !text.ends_with('\n');
12689
12690                    if needs_leading_newline {
12691                        text.insert(0, '\n');
12692                        end
12693                    } else {
12694                        text.push('\n');
12695                        Point::new(rows.start.0, 0)
12696                    }
12697                } else {
12698                    text.push('\n');
12699                    start
12700                };
12701                edits.push((insert_location..insert_location, text));
12702            } else {
12703                // duplicate character-wise
12704                let start = selection.start;
12705                let end = selection.end;
12706                let text = buffer.text_for_range(start..end).collect::<String>();
12707                edits.push((selection.end..selection.end, text));
12708            }
12709        }
12710
12711        self.transact(window, cx, |this, window, cx| {
12712            this.buffer.update(cx, |buffer, cx| {
12713                buffer.edit(edits, None, cx);
12714            });
12715
12716            // When duplicating upward with whole lines, move the cursor to the duplicated line
12717            if upwards && whole_lines {
12718                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12719
12720                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12721                    let mut new_ranges = Vec::new();
12722                    let selections = s.all::<Point>(&display_map);
12723                    let mut selections_iter = selections.iter().peekable();
12724
12725                    while let Some(first_selection) = selections_iter.next() {
12726                        // Group contiguous selections together to find the total row span
12727                        let mut group_selections = vec![first_selection];
12728                        let mut rows = first_selection.spanned_rows(false, &display_map);
12729
12730                        while let Some(next_selection) = selections_iter.peek() {
12731                            let next_rows = next_selection.spanned_rows(false, &display_map);
12732                            if next_rows.start < rows.end {
12733                                rows.end = next_rows.end;
12734                                group_selections.push(selections_iter.next().unwrap());
12735                            } else {
12736                                break;
12737                            }
12738                        }
12739
12740                        let row_count = rows.end.0 - rows.start.0;
12741
12742                        // Move all selections in this group up by the total number of duplicated rows
12743                        for selection in group_selections {
12744                            let new_start = Point::new(
12745                                selection.start.row.saturating_sub(row_count),
12746                                selection.start.column,
12747                            );
12748
12749                            let new_end = Point::new(
12750                                selection.end.row.saturating_sub(row_count),
12751                                selection.end.column,
12752                            );
12753
12754                            new_ranges.push(new_start..new_end);
12755                        }
12756                    }
12757
12758                    s.select_ranges(new_ranges);
12759                });
12760            }
12761
12762            this.request_autoscroll(Autoscroll::fit(), cx);
12763        });
12764    }
12765
12766    pub fn duplicate_line_up(
12767        &mut self,
12768        _: &DuplicateLineUp,
12769        window: &mut Window,
12770        cx: &mut Context<Self>,
12771    ) {
12772        self.duplicate(true, true, window, cx);
12773    }
12774
12775    pub fn duplicate_line_down(
12776        &mut self,
12777        _: &DuplicateLineDown,
12778        window: &mut Window,
12779        cx: &mut Context<Self>,
12780    ) {
12781        self.duplicate(false, true, window, cx);
12782    }
12783
12784    pub fn duplicate_selection(
12785        &mut self,
12786        _: &DuplicateSelection,
12787        window: &mut Window,
12788        cx: &mut Context<Self>,
12789    ) {
12790        self.duplicate(false, false, window, cx);
12791    }
12792
12793    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12795        if self.mode.is_single_line() {
12796            cx.propagate();
12797            return;
12798        }
12799
12800        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12801        let buffer = self.buffer.read(cx).snapshot(cx);
12802
12803        let mut edits = Vec::new();
12804        let mut unfold_ranges = Vec::new();
12805        let mut refold_creases = Vec::new();
12806
12807        let selections = self.selections.all::<Point>(&display_map);
12808        let mut selections = selections.iter().peekable();
12809        let mut contiguous_row_selections = Vec::new();
12810        let mut new_selections = Vec::new();
12811
12812        while let Some(selection) = selections.next() {
12813            // Find all the selections that span a contiguous row range
12814            let (start_row, end_row) = consume_contiguous_rows(
12815                &mut contiguous_row_selections,
12816                selection,
12817                &display_map,
12818                &mut selections,
12819            );
12820
12821            // Move the text spanned by the row range to be before the line preceding the row range
12822            if start_row.0 > 0 {
12823                let range_to_move = Point::new(
12824                    start_row.previous_row().0,
12825                    buffer.line_len(start_row.previous_row()),
12826                )
12827                    ..Point::new(
12828                        end_row.previous_row().0,
12829                        buffer.line_len(end_row.previous_row()),
12830                    );
12831                let insertion_point = display_map
12832                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12833                    .0;
12834
12835                // Don't move lines across excerpts
12836                if buffer
12837                    .excerpt_containing(insertion_point..range_to_move.end)
12838                    .is_some()
12839                {
12840                    let text = buffer
12841                        .text_for_range(range_to_move.clone())
12842                        .flat_map(|s| s.chars())
12843                        .skip(1)
12844                        .chain(['\n'])
12845                        .collect::<String>();
12846
12847                    edits.push((
12848                        buffer.anchor_after(range_to_move.start)
12849                            ..buffer.anchor_before(range_to_move.end),
12850                        String::new(),
12851                    ));
12852                    let insertion_anchor = buffer.anchor_after(insertion_point);
12853                    edits.push((insertion_anchor..insertion_anchor, text));
12854
12855                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12856
12857                    // Move selections up
12858                    new_selections.extend(contiguous_row_selections.drain(..).map(
12859                        |mut selection| {
12860                            selection.start.row -= row_delta;
12861                            selection.end.row -= row_delta;
12862                            selection
12863                        },
12864                    ));
12865
12866                    // Move folds up
12867                    unfold_ranges.push(range_to_move.clone());
12868                    for fold in display_map.folds_in_range(
12869                        buffer.anchor_before(range_to_move.start)
12870                            ..buffer.anchor_after(range_to_move.end),
12871                    ) {
12872                        let mut start = fold.range.start.to_point(&buffer);
12873                        let mut end = fold.range.end.to_point(&buffer);
12874                        start.row -= row_delta;
12875                        end.row -= row_delta;
12876                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12877                    }
12878                }
12879            }
12880
12881            // If we didn't move line(s), preserve the existing selections
12882            new_selections.append(&mut contiguous_row_selections);
12883        }
12884
12885        self.transact(window, cx, |this, window, cx| {
12886            this.unfold_ranges(&unfold_ranges, true, true, cx);
12887            this.buffer.update(cx, |buffer, cx| {
12888                for (range, text) in edits {
12889                    buffer.edit([(range, text)], None, cx);
12890                }
12891            });
12892            this.fold_creases(refold_creases, true, window, cx);
12893            this.change_selections(Default::default(), window, cx, |s| {
12894                s.select(new_selections);
12895            })
12896        });
12897    }
12898
12899    pub fn move_line_down(
12900        &mut self,
12901        _: &MoveLineDown,
12902        window: &mut Window,
12903        cx: &mut Context<Self>,
12904    ) {
12905        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12906        if self.mode.is_single_line() {
12907            cx.propagate();
12908            return;
12909        }
12910
12911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12912        let buffer = self.buffer.read(cx).snapshot(cx);
12913
12914        let mut edits = Vec::new();
12915        let mut unfold_ranges = Vec::new();
12916        let mut refold_creases = Vec::new();
12917
12918        let selections = self.selections.all::<Point>(&display_map);
12919        let mut selections = selections.iter().peekable();
12920        let mut contiguous_row_selections = Vec::new();
12921        let mut new_selections = Vec::new();
12922
12923        while let Some(selection) = selections.next() {
12924            // Find all the selections that span a contiguous row range
12925            let (start_row, end_row) = consume_contiguous_rows(
12926                &mut contiguous_row_selections,
12927                selection,
12928                &display_map,
12929                &mut selections,
12930            );
12931
12932            // Move the text spanned by the row range to be after the last line of the row range
12933            if end_row.0 <= buffer.max_point().row {
12934                let range_to_move =
12935                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12936                let insertion_point = display_map
12937                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12938                    .0;
12939
12940                // Don't move lines across excerpt boundaries
12941                if buffer
12942                    .excerpt_containing(range_to_move.start..insertion_point)
12943                    .is_some()
12944                {
12945                    let mut text = String::from("\n");
12946                    text.extend(buffer.text_for_range(range_to_move.clone()));
12947                    text.pop(); // Drop trailing newline
12948                    edits.push((
12949                        buffer.anchor_after(range_to_move.start)
12950                            ..buffer.anchor_before(range_to_move.end),
12951                        String::new(),
12952                    ));
12953                    let insertion_anchor = buffer.anchor_after(insertion_point);
12954                    edits.push((insertion_anchor..insertion_anchor, text));
12955
12956                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12957
12958                    // Move selections down
12959                    new_selections.extend(contiguous_row_selections.drain(..).map(
12960                        |mut selection| {
12961                            selection.start.row += row_delta;
12962                            selection.end.row += row_delta;
12963                            selection
12964                        },
12965                    ));
12966
12967                    // Move folds down
12968                    unfold_ranges.push(range_to_move.clone());
12969                    for fold in display_map.folds_in_range(
12970                        buffer.anchor_before(range_to_move.start)
12971                            ..buffer.anchor_after(range_to_move.end),
12972                    ) {
12973                        let mut start = fold.range.start.to_point(&buffer);
12974                        let mut end = fold.range.end.to_point(&buffer);
12975                        start.row += row_delta;
12976                        end.row += row_delta;
12977                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12978                    }
12979                }
12980            }
12981
12982            // If we didn't move line(s), preserve the existing selections
12983            new_selections.append(&mut contiguous_row_selections);
12984        }
12985
12986        self.transact(window, cx, |this, window, cx| {
12987            this.unfold_ranges(&unfold_ranges, true, true, cx);
12988            this.buffer.update(cx, |buffer, cx| {
12989                for (range, text) in edits {
12990                    buffer.edit([(range, text)], None, cx);
12991                }
12992            });
12993            this.fold_creases(refold_creases, true, window, cx);
12994            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12995        });
12996    }
12997
12998    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13000        let text_layout_details = &self.text_layout_details(window, cx);
13001        self.transact(window, cx, |this, window, cx| {
13002            let edits = this.change_selections(Default::default(), window, cx, |s| {
13003                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13004                s.move_with(|display_map, selection| {
13005                    if !selection.is_empty() {
13006                        return;
13007                    }
13008
13009                    let mut head = selection.head();
13010                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13011                    if head.column() == display_map.line_len(head.row()) {
13012                        transpose_offset = display_map
13013                            .buffer_snapshot()
13014                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13015                    }
13016
13017                    if transpose_offset == MultiBufferOffset(0) {
13018                        return;
13019                    }
13020
13021                    *head.column_mut() += 1;
13022                    head = display_map.clip_point(head, Bias::Right);
13023                    let goal = SelectionGoal::HorizontalPosition(
13024                        display_map
13025                            .x_for_display_point(head, text_layout_details)
13026                            .into(),
13027                    );
13028                    selection.collapse_to(head, goal);
13029
13030                    let transpose_start = display_map
13031                        .buffer_snapshot()
13032                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13033                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13034                        let transpose_end = display_map
13035                            .buffer_snapshot()
13036                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13037                        if let Some(ch) = display_map
13038                            .buffer_snapshot()
13039                            .chars_at(transpose_start)
13040                            .next()
13041                        {
13042                            edits.push((transpose_start..transpose_offset, String::new()));
13043                            edits.push((transpose_end..transpose_end, ch.to_string()));
13044                        }
13045                    }
13046                });
13047                edits
13048            });
13049            this.buffer
13050                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13051            let selections = this
13052                .selections
13053                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13054            this.change_selections(Default::default(), window, cx, |s| {
13055                s.select(selections);
13056            });
13057        });
13058    }
13059
13060    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13062        if self.mode.is_single_line() {
13063            cx.propagate();
13064            return;
13065        }
13066
13067        self.rewrap_impl(RewrapOptions::default(), cx)
13068    }
13069
13070    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13071        let buffer = self.buffer.read(cx).snapshot(cx);
13072        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13073
13074        #[derive(Clone, Debug, PartialEq)]
13075        enum CommentFormat {
13076            /// single line comment, with prefix for line
13077            Line(String),
13078            /// single line within a block comment, with prefix for line
13079            BlockLine(String),
13080            /// a single line of a block comment that includes the initial delimiter
13081            BlockCommentWithStart(BlockCommentConfig),
13082            /// a single line of a block comment that includes the ending delimiter
13083            BlockCommentWithEnd(BlockCommentConfig),
13084        }
13085
13086        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13087        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13088            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
13089                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13090                .peekable();
13091
13092            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13093                row
13094            } else {
13095                return Vec::new();
13096            };
13097
13098            let language_settings = buffer.language_settings_at(selection.head(), cx);
13099            let language_scope = buffer.language_scope_at(selection.head());
13100
13101            let indent_and_prefix_for_row =
13102                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13103                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13104                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13105                        &language_scope
13106                    {
13107                        let indent_end = Point::new(row, indent.len);
13108                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13109                        let line_text_after_indent = buffer
13110                            .text_for_range(indent_end..line_end)
13111                            .collect::<String>();
13112
13113                        let is_within_comment_override = buffer
13114                            .language_scope_at(indent_end)
13115                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13116                        let comment_delimiters = if is_within_comment_override {
13117                            // we are within a comment syntax node, but we don't
13118                            // yet know what kind of comment: block, doc or line
13119                            match (
13120                                language_scope.documentation_comment(),
13121                                language_scope.block_comment(),
13122                            ) {
13123                                (Some(config), _) | (_, Some(config))
13124                                    if buffer.contains_str_at(indent_end, &config.start) =>
13125                                {
13126                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13127                                }
13128                                (Some(config), _) | (_, Some(config))
13129                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13130                                {
13131                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13132                                }
13133                                (Some(config), _) | (_, Some(config))
13134                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13135                                {
13136                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13137                                }
13138                                (_, _) => language_scope
13139                                    .line_comment_prefixes()
13140                                    .iter()
13141                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13142                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13143                            }
13144                        } else {
13145                            // we not in an overridden comment node, but we may
13146                            // be within a non-overridden line comment node
13147                            language_scope
13148                                .line_comment_prefixes()
13149                                .iter()
13150                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13151                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13152                        };
13153
13154                        let rewrap_prefix = language_scope
13155                            .rewrap_prefixes()
13156                            .iter()
13157                            .find_map(|prefix_regex| {
13158                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13159                                    if mat.start() == 0 {
13160                                        Some(mat.as_str().to_string())
13161                                    } else {
13162                                        None
13163                                    }
13164                                })
13165                            })
13166                            .flatten();
13167                        (comment_delimiters, rewrap_prefix)
13168                    } else {
13169                        (None, None)
13170                    };
13171                    (indent, comment_prefix, rewrap_prefix)
13172                };
13173
13174            let mut ranges = Vec::new();
13175            let from_empty_selection = selection.is_empty();
13176
13177            let mut current_range_start = first_row;
13178            let mut prev_row = first_row;
13179            let (
13180                mut current_range_indent,
13181                mut current_range_comment_delimiters,
13182                mut current_range_rewrap_prefix,
13183            ) = indent_and_prefix_for_row(first_row);
13184
13185            for row in non_blank_rows_iter.skip(1) {
13186                let has_paragraph_break = row > prev_row + 1;
13187
13188                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13189                    indent_and_prefix_for_row(row);
13190
13191                let has_indent_change = row_indent != current_range_indent;
13192                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13193
13194                let has_boundary_change = has_comment_change
13195                    || row_rewrap_prefix.is_some()
13196                    || (has_indent_change && current_range_comment_delimiters.is_some());
13197
13198                if has_paragraph_break || has_boundary_change {
13199                    ranges.push((
13200                        language_settings.clone(),
13201                        Point::new(current_range_start, 0)
13202                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13203                        current_range_indent,
13204                        current_range_comment_delimiters.clone(),
13205                        current_range_rewrap_prefix.clone(),
13206                        from_empty_selection,
13207                    ));
13208                    current_range_start = row;
13209                    current_range_indent = row_indent;
13210                    current_range_comment_delimiters = row_comment_delimiters;
13211                    current_range_rewrap_prefix = row_rewrap_prefix;
13212                }
13213                prev_row = row;
13214            }
13215
13216            ranges.push((
13217                language_settings.clone(),
13218                Point::new(current_range_start, 0)
13219                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13220                current_range_indent,
13221                current_range_comment_delimiters,
13222                current_range_rewrap_prefix,
13223                from_empty_selection,
13224            ));
13225
13226            ranges
13227        });
13228
13229        let mut edits = Vec::new();
13230        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13231
13232        for (
13233            language_settings,
13234            wrap_range,
13235            mut indent_size,
13236            comment_prefix,
13237            rewrap_prefix,
13238            from_empty_selection,
13239        ) in wrap_ranges
13240        {
13241            let mut start_row = wrap_range.start.row;
13242            let mut end_row = wrap_range.end.row;
13243
13244            // Skip selections that overlap with a range that has already been rewrapped.
13245            let selection_range = start_row..end_row;
13246            if rewrapped_row_ranges
13247                .iter()
13248                .any(|range| range.overlaps(&selection_range))
13249            {
13250                continue;
13251            }
13252
13253            let tab_size = language_settings.tab_size;
13254
13255            let (line_prefix, inside_comment) = match &comment_prefix {
13256                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13257                    (Some(prefix.as_str()), true)
13258                }
13259                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13260                    (Some(prefix.as_ref()), true)
13261                }
13262                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13263                    start: _,
13264                    end: _,
13265                    prefix,
13266                    tab_size,
13267                })) => {
13268                    indent_size.len += tab_size;
13269                    (Some(prefix.as_ref()), true)
13270                }
13271                None => (None, false),
13272            };
13273            let indent_prefix = indent_size.chars().collect::<String>();
13274            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13275
13276            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13277                RewrapBehavior::InComments => inside_comment,
13278                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13279                RewrapBehavior::Anywhere => true,
13280            };
13281
13282            let should_rewrap = options.override_language_settings
13283                || allow_rewrap_based_on_language
13284                || self.hard_wrap.is_some();
13285            if !should_rewrap {
13286                continue;
13287            }
13288
13289            if from_empty_selection {
13290                'expand_upwards: while start_row > 0 {
13291                    let prev_row = start_row - 1;
13292                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13293                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13294                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13295                    {
13296                        start_row = prev_row;
13297                    } else {
13298                        break 'expand_upwards;
13299                    }
13300                }
13301
13302                'expand_downwards: while end_row < buffer.max_point().row {
13303                    let next_row = end_row + 1;
13304                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13305                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13306                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13307                    {
13308                        end_row = next_row;
13309                    } else {
13310                        break 'expand_downwards;
13311                    }
13312                }
13313            }
13314
13315            let start = Point::new(start_row, 0);
13316            let start_offset = ToOffset::to_offset(&start, &buffer);
13317            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13318            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13319            let mut first_line_delimiter = None;
13320            let mut last_line_delimiter = None;
13321            let Some(lines_without_prefixes) = selection_text
13322                .lines()
13323                .enumerate()
13324                .map(|(ix, line)| {
13325                    let line_trimmed = line.trim_start();
13326                    if rewrap_prefix.is_some() && ix > 0 {
13327                        Ok(line_trimmed)
13328                    } else if let Some(
13329                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13330                            start,
13331                            prefix,
13332                            end,
13333                            tab_size,
13334                        })
13335                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13336                            start,
13337                            prefix,
13338                            end,
13339                            tab_size,
13340                        }),
13341                    ) = &comment_prefix
13342                    {
13343                        let line_trimmed = line_trimmed
13344                            .strip_prefix(start.as_ref())
13345                            .map(|s| {
13346                                let mut indent_size = indent_size;
13347                                indent_size.len -= tab_size;
13348                                let indent_prefix: String = indent_size.chars().collect();
13349                                first_line_delimiter = Some((indent_prefix, start));
13350                                s.trim_start()
13351                            })
13352                            .unwrap_or(line_trimmed);
13353                        let line_trimmed = line_trimmed
13354                            .strip_suffix(end.as_ref())
13355                            .map(|s| {
13356                                last_line_delimiter = Some(end);
13357                                s.trim_end()
13358                            })
13359                            .unwrap_or(line_trimmed);
13360                        let line_trimmed = line_trimmed
13361                            .strip_prefix(prefix.as_ref())
13362                            .unwrap_or(line_trimmed);
13363                        Ok(line_trimmed)
13364                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13365                        line_trimmed.strip_prefix(prefix).with_context(|| {
13366                            format!("line did not start with prefix {prefix:?}: {line:?}")
13367                        })
13368                    } else {
13369                        line_trimmed
13370                            .strip_prefix(&line_prefix.trim_start())
13371                            .with_context(|| {
13372                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13373                            })
13374                    }
13375                })
13376                .collect::<Result<Vec<_>, _>>()
13377                .log_err()
13378            else {
13379                continue;
13380            };
13381
13382            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13383                buffer
13384                    .language_settings_at(Point::new(start_row, 0), cx)
13385                    .preferred_line_length as usize
13386            });
13387
13388            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13389                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13390            } else {
13391                line_prefix.clone()
13392            };
13393
13394            let wrapped_text = {
13395                let mut wrapped_text = wrap_with_prefix(
13396                    line_prefix,
13397                    subsequent_lines_prefix,
13398                    lines_without_prefixes.join("\n"),
13399                    wrap_column,
13400                    tab_size,
13401                    options.preserve_existing_whitespace,
13402                );
13403
13404                if let Some((indent, delimiter)) = first_line_delimiter {
13405                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13406                }
13407                if let Some(last_line) = last_line_delimiter {
13408                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13409                }
13410
13411                wrapped_text
13412            };
13413
13414            // TODO: should always use char-based diff while still supporting cursor behavior that
13415            // matches vim.
13416            let mut diff_options = DiffOptions::default();
13417            if options.override_language_settings {
13418                diff_options.max_word_diff_len = 0;
13419                diff_options.max_word_diff_line_count = 0;
13420            } else {
13421                diff_options.max_word_diff_len = usize::MAX;
13422                diff_options.max_word_diff_line_count = usize::MAX;
13423            }
13424
13425            for (old_range, new_text) in
13426                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13427            {
13428                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13429                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13430                edits.push((edit_start..edit_end, new_text));
13431            }
13432
13433            rewrapped_row_ranges.push(start_row..=end_row);
13434        }
13435
13436        self.buffer
13437            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13438    }
13439
13440    pub fn cut_common(
13441        &mut self,
13442        cut_no_selection_line: bool,
13443        window: &mut Window,
13444        cx: &mut Context<Self>,
13445    ) -> ClipboardItem {
13446        let mut text = String::new();
13447        let buffer = self.buffer.read(cx).snapshot(cx);
13448        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13449        let mut clipboard_selections = Vec::with_capacity(selections.len());
13450        {
13451            let max_point = buffer.max_point();
13452            let mut is_first = true;
13453            let mut prev_selection_was_entire_line = false;
13454            for selection in &mut selections {
13455                let is_entire_line =
13456                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13457                if is_entire_line {
13458                    selection.start = Point::new(selection.start.row, 0);
13459                    if !selection.is_empty() && selection.end.column == 0 {
13460                        selection.end = cmp::min(max_point, selection.end);
13461                    } else {
13462                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13463                    }
13464                    selection.goal = SelectionGoal::None;
13465                }
13466                if is_first {
13467                    is_first = false;
13468                } else if !prev_selection_was_entire_line {
13469                    text += "\n";
13470                }
13471                prev_selection_was_entire_line = is_entire_line;
13472                let mut len = 0;
13473                for chunk in buffer.text_for_range(selection.start..selection.end) {
13474                    text.push_str(chunk);
13475                    len += chunk.len();
13476                }
13477
13478                clipboard_selections.push(ClipboardSelection::for_buffer(
13479                    len,
13480                    is_entire_line,
13481                    selection.range(),
13482                    &buffer,
13483                    self.project.as_ref(),
13484                    cx,
13485                ));
13486            }
13487        }
13488
13489        self.transact(window, cx, |this, window, cx| {
13490            this.change_selections(Default::default(), window, cx, |s| {
13491                s.select(selections);
13492            });
13493            this.insert("", window, cx);
13494        });
13495        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13496    }
13497
13498    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13499        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13500        let item = self.cut_common(true, window, cx);
13501        cx.write_to_clipboard(item);
13502    }
13503
13504    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13506        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13507            s.move_with(|snapshot, sel| {
13508                if sel.is_empty() {
13509                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13510                }
13511                if sel.is_empty() {
13512                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13513                }
13514            });
13515        });
13516        let item = self.cut_common(false, window, cx);
13517        cx.set_global(KillRing(item))
13518    }
13519
13520    pub fn kill_ring_yank(
13521        &mut self,
13522        _: &KillRingYank,
13523        window: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13527        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13528            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13529                (kill_ring.text().to_string(), kill_ring.metadata_json())
13530            } else {
13531                return;
13532            }
13533        } else {
13534            return;
13535        };
13536        self.do_paste(&text, metadata, false, window, cx);
13537    }
13538
13539    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13540        self.do_copy(true, cx);
13541    }
13542
13543    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13544        self.do_copy(false, cx);
13545    }
13546
13547    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13548        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13549        let buffer = self.buffer.read(cx).read(cx);
13550        let mut text = String::new();
13551
13552        let mut clipboard_selections = Vec::with_capacity(selections.len());
13553        {
13554            let max_point = buffer.max_point();
13555            let mut is_first = true;
13556            let mut prev_selection_was_entire_line = false;
13557            for selection in &selections {
13558                let mut start = selection.start;
13559                let mut end = selection.end;
13560                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13561                let mut add_trailing_newline = false;
13562                if is_entire_line {
13563                    start = Point::new(start.row, 0);
13564                    let next_line_start = Point::new(end.row + 1, 0);
13565                    if next_line_start <= max_point {
13566                        end = next_line_start;
13567                    } else {
13568                        // We're on the last line without a trailing newline.
13569                        // Copy to the end of the line and add a newline afterwards.
13570                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13571                        add_trailing_newline = true;
13572                    }
13573                }
13574
13575                let mut trimmed_selections = Vec::new();
13576                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13577                    let row = MultiBufferRow(start.row);
13578                    let first_indent = buffer.indent_size_for_line(row);
13579                    if first_indent.len == 0 || start.column > first_indent.len {
13580                        trimmed_selections.push(start..end);
13581                    } else {
13582                        trimmed_selections.push(
13583                            Point::new(row.0, first_indent.len)
13584                                ..Point::new(row.0, buffer.line_len(row)),
13585                        );
13586                        for row in start.row + 1..=end.row {
13587                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13588                            if row == end.row {
13589                                line_len = end.column;
13590                            }
13591                            if line_len == 0 {
13592                                trimmed_selections
13593                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13594                                continue;
13595                            }
13596                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13597                            if row_indent_size.len >= first_indent.len {
13598                                trimmed_selections.push(
13599                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13600                                );
13601                            } else {
13602                                trimmed_selections.clear();
13603                                trimmed_selections.push(start..end);
13604                                break;
13605                            }
13606                        }
13607                    }
13608                } else {
13609                    trimmed_selections.push(start..end);
13610                }
13611
13612                let is_multiline_trim = trimmed_selections.len() > 1;
13613                for trimmed_range in trimmed_selections {
13614                    if is_first {
13615                        is_first = false;
13616                    } else if is_multiline_trim || !prev_selection_was_entire_line {
13617                        text += "\n";
13618                    }
13619                    prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13620                    let mut len = 0;
13621                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13622                        text.push_str(chunk);
13623                        len += chunk.len();
13624                    }
13625                    if add_trailing_newline {
13626                        text.push('\n');
13627                        len += 1;
13628                    }
13629                    clipboard_selections.push(ClipboardSelection::for_buffer(
13630                        len,
13631                        is_entire_line,
13632                        trimmed_range,
13633                        &buffer,
13634                        self.project.as_ref(),
13635                        cx,
13636                    ));
13637                }
13638            }
13639        }
13640
13641        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13642            text,
13643            clipboard_selections,
13644        ));
13645    }
13646
13647    pub fn do_paste(
13648        &mut self,
13649        text: &String,
13650        clipboard_selections: Option<Vec<ClipboardSelection>>,
13651        handle_entire_lines: bool,
13652        window: &mut Window,
13653        cx: &mut Context<Self>,
13654    ) {
13655        if self.read_only(cx) {
13656            return;
13657        }
13658
13659        let clipboard_text = Cow::Borrowed(text.as_str());
13660
13661        self.transact(window, cx, |this, window, cx| {
13662            let had_active_edit_prediction = this.has_active_edit_prediction();
13663            let display_map = this.display_snapshot(cx);
13664            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13665            let cursor_offset = this
13666                .selections
13667                .last::<MultiBufferOffset>(&display_map)
13668                .head();
13669
13670            if let Some(mut clipboard_selections) = clipboard_selections {
13671                let all_selections_were_entire_line =
13672                    clipboard_selections.iter().all(|s| s.is_entire_line);
13673                let first_selection_indent_column =
13674                    clipboard_selections.first().map(|s| s.first_line_indent);
13675                if clipboard_selections.len() != old_selections.len() {
13676                    clipboard_selections.drain(..);
13677                }
13678                let mut auto_indent_on_paste = true;
13679
13680                this.buffer.update(cx, |buffer, cx| {
13681                    let snapshot = buffer.read(cx);
13682                    auto_indent_on_paste = snapshot
13683                        .language_settings_at(cursor_offset, cx)
13684                        .auto_indent_on_paste;
13685
13686                    let mut start_offset = 0;
13687                    let mut edits = Vec::new();
13688                    let mut original_indent_columns = Vec::new();
13689                    for (ix, selection) in old_selections.iter().enumerate() {
13690                        let to_insert;
13691                        let entire_line;
13692                        let original_indent_column;
13693                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13694                            let end_offset = start_offset + clipboard_selection.len;
13695                            to_insert = &clipboard_text[start_offset..end_offset];
13696                            entire_line = clipboard_selection.is_entire_line;
13697                            start_offset = if entire_line {
13698                                end_offset
13699                            } else {
13700                                end_offset + 1
13701                            };
13702                            original_indent_column = Some(clipboard_selection.first_line_indent);
13703                        } else {
13704                            to_insert = &*clipboard_text;
13705                            entire_line = all_selections_were_entire_line;
13706                            original_indent_column = first_selection_indent_column
13707                        }
13708
13709                        let (range, to_insert) =
13710                            if selection.is_empty() && handle_entire_lines && entire_line {
13711                                // If the corresponding selection was empty when this slice of the
13712                                // clipboard text was written, then the entire line containing the
13713                                // selection was copied. If this selection is also currently empty,
13714                                // then paste the line before the current line of the buffer.
13715                                let column = selection.start.to_point(&snapshot).column as usize;
13716                                let line_start = selection.start - column;
13717                                (line_start..line_start, Cow::Borrowed(to_insert))
13718                            } else {
13719                                let language = snapshot.language_at(selection.head());
13720                                let range = selection.range();
13721                                if let Some(language) = language
13722                                    && language.name() == "Markdown".into()
13723                                {
13724                                    edit_for_markdown_paste(
13725                                        &snapshot,
13726                                        range,
13727                                        to_insert,
13728                                        url::Url::parse(to_insert).ok(),
13729                                    )
13730                                } else {
13731                                    (range, Cow::Borrowed(to_insert))
13732                                }
13733                            };
13734
13735                        edits.push((range, to_insert));
13736                        original_indent_columns.push(original_indent_column);
13737                    }
13738                    drop(snapshot);
13739
13740                    buffer.edit(
13741                        edits,
13742                        if auto_indent_on_paste {
13743                            Some(AutoindentMode::Block {
13744                                original_indent_columns,
13745                            })
13746                        } else {
13747                            None
13748                        },
13749                        cx,
13750                    );
13751                });
13752
13753                let selections = this
13754                    .selections
13755                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13756                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13757            } else {
13758                let url = url::Url::parse(&clipboard_text).ok();
13759
13760                let auto_indent_mode = if !clipboard_text.is_empty() {
13761                    Some(AutoindentMode::Block {
13762                        original_indent_columns: Vec::new(),
13763                    })
13764                } else {
13765                    None
13766                };
13767
13768                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13769                    let snapshot = buffer.snapshot(cx);
13770
13771                    let anchors = old_selections
13772                        .iter()
13773                        .map(|s| {
13774                            let anchor = snapshot.anchor_after(s.head());
13775                            s.map(|_| anchor)
13776                        })
13777                        .collect::<Vec<_>>();
13778
13779                    let mut edits = Vec::new();
13780
13781                    for selection in old_selections.iter() {
13782                        let language = snapshot.language_at(selection.head());
13783                        let range = selection.range();
13784
13785                        let (edit_range, edit_text) = if let Some(language) = language
13786                            && language.name() == "Markdown".into()
13787                        {
13788                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13789                        } else {
13790                            (range, clipboard_text.clone())
13791                        };
13792
13793                        edits.push((edit_range, edit_text));
13794                    }
13795
13796                    drop(snapshot);
13797                    buffer.edit(edits, auto_indent_mode, cx);
13798
13799                    anchors
13800                });
13801
13802                this.change_selections(Default::default(), window, cx, |s| {
13803                    s.select_anchors(selection_anchors);
13804                });
13805            }
13806
13807            //   🤔                 |    ..     | show_in_menu |
13808            // | ..                  |   true        true
13809            // | had_edit_prediction |   false       true
13810
13811            let trigger_in_words =
13812                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13813
13814            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13815        });
13816    }
13817
13818    pub fn diff_clipboard_with_selection(
13819        &mut self,
13820        _: &DiffClipboardWithSelection,
13821        window: &mut Window,
13822        cx: &mut Context<Self>,
13823    ) {
13824        let selections = self
13825            .selections
13826            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13827
13828        if selections.is_empty() {
13829            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13830            return;
13831        };
13832
13833        let clipboard_text = match cx.read_from_clipboard() {
13834            Some(item) => match item.entries().first() {
13835                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13836                _ => None,
13837            },
13838            None => None,
13839        };
13840
13841        let Some(clipboard_text) = clipboard_text else {
13842            log::warn!("Clipboard doesn't contain text.");
13843            return;
13844        };
13845
13846        window.dispatch_action(
13847            Box::new(DiffClipboardWithSelectionData {
13848                clipboard_text,
13849                editor: cx.entity(),
13850            }),
13851            cx,
13852        );
13853    }
13854
13855    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13856        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13857        if let Some(item) = cx.read_from_clipboard() {
13858            let entries = item.entries();
13859
13860            match entries.first() {
13861                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13862                // of all the pasted entries.
13863                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13864                    .do_paste(
13865                        clipboard_string.text(),
13866                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13867                        true,
13868                        window,
13869                        cx,
13870                    ),
13871                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13872            }
13873        }
13874    }
13875
13876    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13877        if self.read_only(cx) {
13878            return;
13879        }
13880
13881        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13882
13883        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13884            if let Some((selections, _)) =
13885                self.selection_history.transaction(transaction_id).cloned()
13886            {
13887                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13888                    s.select_anchors(selections.to_vec());
13889                });
13890            } else {
13891                log::error!(
13892                    "No entry in selection_history found for undo. \
13893                     This may correspond to a bug where undo does not update the selection. \
13894                     If this is occurring, please add details to \
13895                     https://github.com/zed-industries/zed/issues/22692"
13896                );
13897            }
13898            self.request_autoscroll(Autoscroll::fit(), cx);
13899            self.unmark_text(window, cx);
13900            self.refresh_edit_prediction(true, false, window, cx);
13901            cx.emit(EditorEvent::Edited { transaction_id });
13902            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13903        }
13904    }
13905
13906    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13907        if self.read_only(cx) {
13908            return;
13909        }
13910
13911        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13912
13913        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13914            if let Some((_, Some(selections))) =
13915                self.selection_history.transaction(transaction_id).cloned()
13916            {
13917                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13918                    s.select_anchors(selections.to_vec());
13919                });
13920            } else {
13921                log::error!(
13922                    "No entry in selection_history found for redo. \
13923                     This may correspond to a bug where undo does not update the selection. \
13924                     If this is occurring, please add details to \
13925                     https://github.com/zed-industries/zed/issues/22692"
13926                );
13927            }
13928            self.request_autoscroll(Autoscroll::fit(), cx);
13929            self.unmark_text(window, cx);
13930            self.refresh_edit_prediction(true, false, window, cx);
13931            cx.emit(EditorEvent::Edited { transaction_id });
13932        }
13933    }
13934
13935    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13936        self.buffer
13937            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13938    }
13939
13940    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13941        self.buffer
13942            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13943    }
13944
13945    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_with(|map, selection| {
13949                let cursor = if selection.is_empty() {
13950                    movement::left(map, selection.start)
13951                } else {
13952                    selection.start
13953                };
13954                selection.collapse_to(cursor, SelectionGoal::None);
13955            });
13956        })
13957    }
13958
13959    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13961        self.change_selections(Default::default(), window, cx, |s| {
13962            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13963        })
13964    }
13965
13966    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.move_with(|map, selection| {
13970                let cursor = if selection.is_empty() {
13971                    movement::right(map, selection.end)
13972                } else {
13973                    selection.end
13974                };
13975                selection.collapse_to(cursor, SelectionGoal::None)
13976            });
13977        })
13978    }
13979
13980    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13982        self.change_selections(Default::default(), window, cx, |s| {
13983            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13984        });
13985    }
13986
13987    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13988        if self.take_rename(true, window, cx).is_some() {
13989            return;
13990        }
13991
13992        if self.mode.is_single_line() {
13993            cx.propagate();
13994            return;
13995        }
13996
13997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13998
13999        let text_layout_details = &self.text_layout_details(window, cx);
14000        let selection_count = self.selections.count();
14001        let first_selection = self.selections.first_anchor();
14002
14003        self.change_selections(Default::default(), window, cx, |s| {
14004            s.move_with(|map, selection| {
14005                if !selection.is_empty() {
14006                    selection.goal = SelectionGoal::None;
14007                }
14008                let (cursor, goal) = movement::up(
14009                    map,
14010                    selection.start,
14011                    selection.goal,
14012                    false,
14013                    text_layout_details,
14014                );
14015                selection.collapse_to(cursor, goal);
14016            });
14017        });
14018
14019        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14020        {
14021            cx.propagate();
14022        }
14023    }
14024
14025    pub fn move_up_by_lines(
14026        &mut self,
14027        action: &MoveUpByLines,
14028        window: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) {
14031        if self.take_rename(true, window, cx).is_some() {
14032            return;
14033        }
14034
14035        if self.mode.is_single_line() {
14036            cx.propagate();
14037            return;
14038        }
14039
14040        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14041
14042        let text_layout_details = &self.text_layout_details(window, cx);
14043
14044        self.change_selections(Default::default(), window, cx, |s| {
14045            s.move_with(|map, selection| {
14046                if !selection.is_empty() {
14047                    selection.goal = SelectionGoal::None;
14048                }
14049                let (cursor, goal) = movement::up_by_rows(
14050                    map,
14051                    selection.start,
14052                    action.lines,
14053                    selection.goal,
14054                    false,
14055                    text_layout_details,
14056                );
14057                selection.collapse_to(cursor, goal);
14058            });
14059        })
14060    }
14061
14062    pub fn move_down_by_lines(
14063        &mut self,
14064        action: &MoveDownByLines,
14065        window: &mut Window,
14066        cx: &mut Context<Self>,
14067    ) {
14068        if self.take_rename(true, window, cx).is_some() {
14069            return;
14070        }
14071
14072        if self.mode.is_single_line() {
14073            cx.propagate();
14074            return;
14075        }
14076
14077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14078
14079        let text_layout_details = &self.text_layout_details(window, cx);
14080
14081        self.change_selections(Default::default(), window, cx, |s| {
14082            s.move_with(|map, selection| {
14083                if !selection.is_empty() {
14084                    selection.goal = SelectionGoal::None;
14085                }
14086                let (cursor, goal) = movement::down_by_rows(
14087                    map,
14088                    selection.start,
14089                    action.lines,
14090                    selection.goal,
14091                    false,
14092                    text_layout_details,
14093                );
14094                selection.collapse_to(cursor, goal);
14095            });
14096        })
14097    }
14098
14099    pub fn select_down_by_lines(
14100        &mut self,
14101        action: &SelectDownByLines,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) {
14105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14106        let text_layout_details = &self.text_layout_details(window, cx);
14107        self.change_selections(Default::default(), window, cx, |s| {
14108            s.move_heads_with(|map, head, goal| {
14109                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14110            })
14111        })
14112    }
14113
14114    pub fn select_up_by_lines(
14115        &mut self,
14116        action: &SelectUpByLines,
14117        window: &mut Window,
14118        cx: &mut Context<Self>,
14119    ) {
14120        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14121        let text_layout_details = &self.text_layout_details(window, cx);
14122        self.change_selections(Default::default(), window, cx, |s| {
14123            s.move_heads_with(|map, head, goal| {
14124                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14125            })
14126        })
14127    }
14128
14129    pub fn select_page_up(
14130        &mut self,
14131        _: &SelectPageUp,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) {
14135        let Some(row_count) = self.visible_row_count() else {
14136            return;
14137        };
14138
14139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14140
14141        let text_layout_details = &self.text_layout_details(window, cx);
14142
14143        self.change_selections(Default::default(), window, cx, |s| {
14144            s.move_heads_with(|map, head, goal| {
14145                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14146            })
14147        })
14148    }
14149
14150    pub fn move_page_up(
14151        &mut self,
14152        action: &MovePageUp,
14153        window: &mut Window,
14154        cx: &mut Context<Self>,
14155    ) {
14156        if self.take_rename(true, window, cx).is_some() {
14157            return;
14158        }
14159
14160        if self
14161            .context_menu
14162            .borrow_mut()
14163            .as_mut()
14164            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14165            .unwrap_or(false)
14166        {
14167            return;
14168        }
14169
14170        if matches!(self.mode, EditorMode::SingleLine) {
14171            cx.propagate();
14172            return;
14173        }
14174
14175        let Some(row_count) = self.visible_row_count() else {
14176            return;
14177        };
14178
14179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14180
14181        let effects = if action.center_cursor {
14182            SelectionEffects::scroll(Autoscroll::center())
14183        } else {
14184            SelectionEffects::default()
14185        };
14186
14187        let text_layout_details = &self.text_layout_details(window, cx);
14188
14189        self.change_selections(effects, window, cx, |s| {
14190            s.move_with(|map, selection| {
14191                if !selection.is_empty() {
14192                    selection.goal = SelectionGoal::None;
14193                }
14194                let (cursor, goal) = movement::up_by_rows(
14195                    map,
14196                    selection.end,
14197                    row_count,
14198                    selection.goal,
14199                    false,
14200                    text_layout_details,
14201                );
14202                selection.collapse_to(cursor, goal);
14203            });
14204        });
14205    }
14206
14207    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14209        let text_layout_details = &self.text_layout_details(window, cx);
14210        self.change_selections(Default::default(), window, cx, |s| {
14211            s.move_heads_with(|map, head, goal| {
14212                movement::up(map, head, goal, false, text_layout_details)
14213            })
14214        })
14215    }
14216
14217    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14218        self.take_rename(true, window, cx);
14219
14220        if self.mode.is_single_line() {
14221            cx.propagate();
14222            return;
14223        }
14224
14225        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14226
14227        let text_layout_details = &self.text_layout_details(window, cx);
14228        let selection_count = self.selections.count();
14229        let first_selection = self.selections.first_anchor();
14230
14231        self.change_selections(Default::default(), window, cx, |s| {
14232            s.move_with(|map, selection| {
14233                if !selection.is_empty() {
14234                    selection.goal = SelectionGoal::None;
14235                }
14236                let (cursor, goal) = movement::down(
14237                    map,
14238                    selection.end,
14239                    selection.goal,
14240                    false,
14241                    text_layout_details,
14242                );
14243                selection.collapse_to(cursor, goal);
14244            });
14245        });
14246
14247        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14248        {
14249            cx.propagate();
14250        }
14251    }
14252
14253    pub fn select_page_down(
14254        &mut self,
14255        _: &SelectPageDown,
14256        window: &mut Window,
14257        cx: &mut Context<Self>,
14258    ) {
14259        let Some(row_count) = self.visible_row_count() else {
14260            return;
14261        };
14262
14263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14264
14265        let text_layout_details = &self.text_layout_details(window, cx);
14266
14267        self.change_selections(Default::default(), window, cx, |s| {
14268            s.move_heads_with(|map, head, goal| {
14269                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14270            })
14271        })
14272    }
14273
14274    pub fn move_page_down(
14275        &mut self,
14276        action: &MovePageDown,
14277        window: &mut Window,
14278        cx: &mut Context<Self>,
14279    ) {
14280        if self.take_rename(true, window, cx).is_some() {
14281            return;
14282        }
14283
14284        if self
14285            .context_menu
14286            .borrow_mut()
14287            .as_mut()
14288            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14289            .unwrap_or(false)
14290        {
14291            return;
14292        }
14293
14294        if matches!(self.mode, EditorMode::SingleLine) {
14295            cx.propagate();
14296            return;
14297        }
14298
14299        let Some(row_count) = self.visible_row_count() else {
14300            return;
14301        };
14302
14303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14304
14305        let effects = if action.center_cursor {
14306            SelectionEffects::scroll(Autoscroll::center())
14307        } else {
14308            SelectionEffects::default()
14309        };
14310
14311        let text_layout_details = &self.text_layout_details(window, cx);
14312        self.change_selections(effects, window, cx, |s| {
14313            s.move_with(|map, selection| {
14314                if !selection.is_empty() {
14315                    selection.goal = SelectionGoal::None;
14316                }
14317                let (cursor, goal) = movement::down_by_rows(
14318                    map,
14319                    selection.end,
14320                    row_count,
14321                    selection.goal,
14322                    false,
14323                    text_layout_details,
14324                );
14325                selection.collapse_to(cursor, goal);
14326            });
14327        });
14328    }
14329
14330    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14332        let text_layout_details = &self.text_layout_details(window, cx);
14333        self.change_selections(Default::default(), window, cx, |s| {
14334            s.move_heads_with(|map, head, goal| {
14335                movement::down(map, head, goal, false, text_layout_details)
14336            })
14337        });
14338    }
14339
14340    pub fn context_menu_first(
14341        &mut self,
14342        _: &ContextMenuFirst,
14343        window: &mut Window,
14344        cx: &mut Context<Self>,
14345    ) {
14346        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14347            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14348        }
14349    }
14350
14351    pub fn context_menu_prev(
14352        &mut self,
14353        _: &ContextMenuPrevious,
14354        window: &mut Window,
14355        cx: &mut Context<Self>,
14356    ) {
14357        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14358            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14359        }
14360    }
14361
14362    pub fn context_menu_next(
14363        &mut self,
14364        _: &ContextMenuNext,
14365        window: &mut Window,
14366        cx: &mut Context<Self>,
14367    ) {
14368        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14369            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14370        }
14371    }
14372
14373    pub fn context_menu_last(
14374        &mut self,
14375        _: &ContextMenuLast,
14376        window: &mut Window,
14377        cx: &mut Context<Self>,
14378    ) {
14379        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14380            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14381        }
14382    }
14383
14384    pub fn signature_help_prev(
14385        &mut self,
14386        _: &SignatureHelpPrevious,
14387        _: &mut Window,
14388        cx: &mut Context<Self>,
14389    ) {
14390        if let Some(popover) = self.signature_help_state.popover_mut() {
14391            if popover.current_signature == 0 {
14392                popover.current_signature = popover.signatures.len() - 1;
14393            } else {
14394                popover.current_signature -= 1;
14395            }
14396            cx.notify();
14397        }
14398    }
14399
14400    pub fn signature_help_next(
14401        &mut self,
14402        _: &SignatureHelpNext,
14403        _: &mut Window,
14404        cx: &mut Context<Self>,
14405    ) {
14406        if let Some(popover) = self.signature_help_state.popover_mut() {
14407            if popover.current_signature + 1 == popover.signatures.len() {
14408                popover.current_signature = 0;
14409            } else {
14410                popover.current_signature += 1;
14411            }
14412            cx.notify();
14413        }
14414    }
14415
14416    pub fn move_to_previous_word_start(
14417        &mut self,
14418        _: &MoveToPreviousWordStart,
14419        window: &mut Window,
14420        cx: &mut Context<Self>,
14421    ) {
14422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14423        self.change_selections(Default::default(), window, cx, |s| {
14424            s.move_cursors_with(|map, head, _| {
14425                (
14426                    movement::previous_word_start(map, head),
14427                    SelectionGoal::None,
14428                )
14429            });
14430        })
14431    }
14432
14433    pub fn move_to_previous_subword_start(
14434        &mut self,
14435        _: &MoveToPreviousSubwordStart,
14436        window: &mut Window,
14437        cx: &mut Context<Self>,
14438    ) {
14439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14440        self.change_selections(Default::default(), window, cx, |s| {
14441            s.move_cursors_with(|map, head, _| {
14442                (
14443                    movement::previous_subword_start(map, head),
14444                    SelectionGoal::None,
14445                )
14446            });
14447        })
14448    }
14449
14450    pub fn select_to_previous_word_start(
14451        &mut self,
14452        _: &SelectToPreviousWordStart,
14453        window: &mut Window,
14454        cx: &mut Context<Self>,
14455    ) {
14456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14457        self.change_selections(Default::default(), window, cx, |s| {
14458            s.move_heads_with(|map, head, _| {
14459                (
14460                    movement::previous_word_start(map, head),
14461                    SelectionGoal::None,
14462                )
14463            });
14464        })
14465    }
14466
14467    pub fn select_to_previous_subword_start(
14468        &mut self,
14469        _: &SelectToPreviousSubwordStart,
14470        window: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) {
14473        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14474        self.change_selections(Default::default(), window, cx, |s| {
14475            s.move_heads_with(|map, head, _| {
14476                (
14477                    movement::previous_subword_start(map, head),
14478                    SelectionGoal::None,
14479                )
14480            });
14481        })
14482    }
14483
14484    pub fn delete_to_previous_word_start(
14485        &mut self,
14486        action: &DeleteToPreviousWordStart,
14487        window: &mut Window,
14488        cx: &mut Context<Self>,
14489    ) {
14490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14491        self.transact(window, cx, |this, window, cx| {
14492            this.select_autoclose_pair(window, cx);
14493            this.change_selections(Default::default(), window, cx, |s| {
14494                s.move_with(|map, selection| {
14495                    if selection.is_empty() {
14496                        let mut cursor = if action.ignore_newlines {
14497                            movement::previous_word_start(map, selection.head())
14498                        } else {
14499                            movement::previous_word_start_or_newline(map, selection.head())
14500                        };
14501                        cursor = movement::adjust_greedy_deletion(
14502                            map,
14503                            selection.head(),
14504                            cursor,
14505                            action.ignore_brackets,
14506                        );
14507                        selection.set_head(cursor, SelectionGoal::None);
14508                    }
14509                });
14510            });
14511            this.insert("", window, cx);
14512        });
14513    }
14514
14515    pub fn delete_to_previous_subword_start(
14516        &mut self,
14517        action: &DeleteToPreviousSubwordStart,
14518        window: &mut Window,
14519        cx: &mut Context<Self>,
14520    ) {
14521        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14522        self.transact(window, cx, |this, window, cx| {
14523            this.select_autoclose_pair(window, cx);
14524            this.change_selections(Default::default(), window, cx, |s| {
14525                s.move_with(|map, selection| {
14526                    if selection.is_empty() {
14527                        let mut cursor = if action.ignore_newlines {
14528                            movement::previous_subword_start(map, selection.head())
14529                        } else {
14530                            movement::previous_subword_start_or_newline(map, selection.head())
14531                        };
14532                        cursor = movement::adjust_greedy_deletion(
14533                            map,
14534                            selection.head(),
14535                            cursor,
14536                            action.ignore_brackets,
14537                        );
14538                        selection.set_head(cursor, SelectionGoal::None);
14539                    }
14540                });
14541            });
14542            this.insert("", window, cx);
14543        });
14544    }
14545
14546    pub fn move_to_next_word_end(
14547        &mut self,
14548        _: &MoveToNextWordEnd,
14549        window: &mut Window,
14550        cx: &mut Context<Self>,
14551    ) {
14552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14553        self.change_selections(Default::default(), window, cx, |s| {
14554            s.move_cursors_with(|map, head, _| {
14555                (movement::next_word_end(map, head), SelectionGoal::None)
14556            });
14557        })
14558    }
14559
14560    pub fn move_to_next_subword_end(
14561        &mut self,
14562        _: &MoveToNextSubwordEnd,
14563        window: &mut Window,
14564        cx: &mut Context<Self>,
14565    ) {
14566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14567        self.change_selections(Default::default(), window, cx, |s| {
14568            s.move_cursors_with(|map, head, _| {
14569                (movement::next_subword_end(map, head), SelectionGoal::None)
14570            });
14571        })
14572    }
14573
14574    pub fn select_to_next_word_end(
14575        &mut self,
14576        _: &SelectToNextWordEnd,
14577        window: &mut Window,
14578        cx: &mut Context<Self>,
14579    ) {
14580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14581        self.change_selections(Default::default(), window, cx, |s| {
14582            s.move_heads_with(|map, head, _| {
14583                (movement::next_word_end(map, head), SelectionGoal::None)
14584            });
14585        })
14586    }
14587
14588    pub fn select_to_next_subword_end(
14589        &mut self,
14590        _: &SelectToNextSubwordEnd,
14591        window: &mut Window,
14592        cx: &mut Context<Self>,
14593    ) {
14594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14595        self.change_selections(Default::default(), window, cx, |s| {
14596            s.move_heads_with(|map, head, _| {
14597                (movement::next_subword_end(map, head), SelectionGoal::None)
14598            });
14599        })
14600    }
14601
14602    pub fn delete_to_next_word_end(
14603        &mut self,
14604        action: &DeleteToNextWordEnd,
14605        window: &mut Window,
14606        cx: &mut Context<Self>,
14607    ) {
14608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14609        self.transact(window, cx, |this, window, cx| {
14610            this.change_selections(Default::default(), window, cx, |s| {
14611                s.move_with(|map, selection| {
14612                    if selection.is_empty() {
14613                        let mut cursor = if action.ignore_newlines {
14614                            movement::next_word_end(map, selection.head())
14615                        } else {
14616                            movement::next_word_end_or_newline(map, selection.head())
14617                        };
14618                        cursor = movement::adjust_greedy_deletion(
14619                            map,
14620                            selection.head(),
14621                            cursor,
14622                            action.ignore_brackets,
14623                        );
14624                        selection.set_head(cursor, SelectionGoal::None);
14625                    }
14626                });
14627            });
14628            this.insert("", window, cx);
14629        });
14630    }
14631
14632    pub fn delete_to_next_subword_end(
14633        &mut self,
14634        action: &DeleteToNextSubwordEnd,
14635        window: &mut Window,
14636        cx: &mut Context<Self>,
14637    ) {
14638        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14639        self.transact(window, cx, |this, window, cx| {
14640            this.change_selections(Default::default(), window, cx, |s| {
14641                s.move_with(|map, selection| {
14642                    if selection.is_empty() {
14643                        let mut cursor = if action.ignore_newlines {
14644                            movement::next_subword_end(map, selection.head())
14645                        } else {
14646                            movement::next_subword_end_or_newline(map, selection.head())
14647                        };
14648                        cursor = movement::adjust_greedy_deletion(
14649                            map,
14650                            selection.head(),
14651                            cursor,
14652                            action.ignore_brackets,
14653                        );
14654                        selection.set_head(cursor, SelectionGoal::None);
14655                    }
14656                });
14657            });
14658            this.insert("", window, cx);
14659        });
14660    }
14661
14662    pub fn move_to_beginning_of_line(
14663        &mut self,
14664        action: &MoveToBeginningOfLine,
14665        window: &mut Window,
14666        cx: &mut Context<Self>,
14667    ) {
14668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14669        self.change_selections(Default::default(), window, cx, |s| {
14670            s.move_cursors_with(|map, head, _| {
14671                (
14672                    movement::indented_line_beginning(
14673                        map,
14674                        head,
14675                        action.stop_at_soft_wraps,
14676                        action.stop_at_indent,
14677                    ),
14678                    SelectionGoal::None,
14679                )
14680            });
14681        })
14682    }
14683
14684    pub fn select_to_beginning_of_line(
14685        &mut self,
14686        action: &SelectToBeginningOfLine,
14687        window: &mut Window,
14688        cx: &mut Context<Self>,
14689    ) {
14690        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14691        self.change_selections(Default::default(), window, cx, |s| {
14692            s.move_heads_with(|map, head, _| {
14693                (
14694                    movement::indented_line_beginning(
14695                        map,
14696                        head,
14697                        action.stop_at_soft_wraps,
14698                        action.stop_at_indent,
14699                    ),
14700                    SelectionGoal::None,
14701                )
14702            });
14703        });
14704    }
14705
14706    pub fn delete_to_beginning_of_line(
14707        &mut self,
14708        action: &DeleteToBeginningOfLine,
14709        window: &mut Window,
14710        cx: &mut Context<Self>,
14711    ) {
14712        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14713        self.transact(window, cx, |this, window, cx| {
14714            this.change_selections(Default::default(), window, cx, |s| {
14715                s.move_with(|_, selection| {
14716                    selection.reversed = true;
14717                });
14718            });
14719
14720            this.select_to_beginning_of_line(
14721                &SelectToBeginningOfLine {
14722                    stop_at_soft_wraps: false,
14723                    stop_at_indent: action.stop_at_indent,
14724                },
14725                window,
14726                cx,
14727            );
14728            this.backspace(&Backspace, window, cx);
14729        });
14730    }
14731
14732    pub fn move_to_end_of_line(
14733        &mut self,
14734        action: &MoveToEndOfLine,
14735        window: &mut Window,
14736        cx: &mut Context<Self>,
14737    ) {
14738        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14739        self.change_selections(Default::default(), window, cx, |s| {
14740            s.move_cursors_with(|map, head, _| {
14741                (
14742                    movement::line_end(map, head, action.stop_at_soft_wraps),
14743                    SelectionGoal::None,
14744                )
14745            });
14746        })
14747    }
14748
14749    pub fn select_to_end_of_line(
14750        &mut self,
14751        action: &SelectToEndOfLine,
14752        window: &mut Window,
14753        cx: &mut Context<Self>,
14754    ) {
14755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14756        self.change_selections(Default::default(), window, cx, |s| {
14757            s.move_heads_with(|map, head, _| {
14758                (
14759                    movement::line_end(map, head, action.stop_at_soft_wraps),
14760                    SelectionGoal::None,
14761                )
14762            });
14763        })
14764    }
14765
14766    pub fn delete_to_end_of_line(
14767        &mut self,
14768        _: &DeleteToEndOfLine,
14769        window: &mut Window,
14770        cx: &mut Context<Self>,
14771    ) {
14772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14773        self.transact(window, cx, |this, window, cx| {
14774            this.select_to_end_of_line(
14775                &SelectToEndOfLine {
14776                    stop_at_soft_wraps: false,
14777                },
14778                window,
14779                cx,
14780            );
14781            this.delete(&Delete, window, cx);
14782        });
14783    }
14784
14785    pub fn cut_to_end_of_line(
14786        &mut self,
14787        action: &CutToEndOfLine,
14788        window: &mut Window,
14789        cx: &mut Context<Self>,
14790    ) {
14791        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14792        self.transact(window, cx, |this, window, cx| {
14793            this.select_to_end_of_line(
14794                &SelectToEndOfLine {
14795                    stop_at_soft_wraps: false,
14796                },
14797                window,
14798                cx,
14799            );
14800            if !action.stop_at_newlines {
14801                this.change_selections(Default::default(), window, cx, |s| {
14802                    s.move_with(|_, sel| {
14803                        if sel.is_empty() {
14804                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14805                        }
14806                    });
14807                });
14808            }
14809            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14810            let item = this.cut_common(false, window, cx);
14811            cx.write_to_clipboard(item);
14812        });
14813    }
14814
14815    pub fn move_to_start_of_paragraph(
14816        &mut self,
14817        _: &MoveToStartOfParagraph,
14818        window: &mut Window,
14819        cx: &mut Context<Self>,
14820    ) {
14821        if matches!(self.mode, EditorMode::SingleLine) {
14822            cx.propagate();
14823            return;
14824        }
14825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14826        self.change_selections(Default::default(), window, cx, |s| {
14827            s.move_with(|map, selection| {
14828                selection.collapse_to(
14829                    movement::start_of_paragraph(map, selection.head(), 1),
14830                    SelectionGoal::None,
14831                )
14832            });
14833        })
14834    }
14835
14836    pub fn move_to_end_of_paragraph(
14837        &mut self,
14838        _: &MoveToEndOfParagraph,
14839        window: &mut Window,
14840        cx: &mut Context<Self>,
14841    ) {
14842        if matches!(self.mode, EditorMode::SingleLine) {
14843            cx.propagate();
14844            return;
14845        }
14846        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14847        self.change_selections(Default::default(), window, cx, |s| {
14848            s.move_with(|map, selection| {
14849                selection.collapse_to(
14850                    movement::end_of_paragraph(map, selection.head(), 1),
14851                    SelectionGoal::None,
14852                )
14853            });
14854        })
14855    }
14856
14857    pub fn select_to_start_of_paragraph(
14858        &mut self,
14859        _: &SelectToStartOfParagraph,
14860        window: &mut Window,
14861        cx: &mut Context<Self>,
14862    ) {
14863        if matches!(self.mode, EditorMode::SingleLine) {
14864            cx.propagate();
14865            return;
14866        }
14867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14868        self.change_selections(Default::default(), window, cx, |s| {
14869            s.move_heads_with(|map, head, _| {
14870                (
14871                    movement::start_of_paragraph(map, head, 1),
14872                    SelectionGoal::None,
14873                )
14874            });
14875        })
14876    }
14877
14878    pub fn select_to_end_of_paragraph(
14879        &mut self,
14880        _: &SelectToEndOfParagraph,
14881        window: &mut Window,
14882        cx: &mut Context<Self>,
14883    ) {
14884        if matches!(self.mode, EditorMode::SingleLine) {
14885            cx.propagate();
14886            return;
14887        }
14888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14889        self.change_selections(Default::default(), window, cx, |s| {
14890            s.move_heads_with(|map, head, _| {
14891                (
14892                    movement::end_of_paragraph(map, head, 1),
14893                    SelectionGoal::None,
14894                )
14895            });
14896        })
14897    }
14898
14899    pub fn move_to_start_of_excerpt(
14900        &mut self,
14901        _: &MoveToStartOfExcerpt,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) {
14905        if matches!(self.mode, EditorMode::SingleLine) {
14906            cx.propagate();
14907            return;
14908        }
14909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14910        self.change_selections(Default::default(), window, cx, |s| {
14911            s.move_with(|map, selection| {
14912                selection.collapse_to(
14913                    movement::start_of_excerpt(
14914                        map,
14915                        selection.head(),
14916                        workspace::searchable::Direction::Prev,
14917                    ),
14918                    SelectionGoal::None,
14919                )
14920            });
14921        })
14922    }
14923
14924    pub fn move_to_start_of_next_excerpt(
14925        &mut self,
14926        _: &MoveToStartOfNextExcerpt,
14927        window: &mut Window,
14928        cx: &mut Context<Self>,
14929    ) {
14930        if matches!(self.mode, EditorMode::SingleLine) {
14931            cx.propagate();
14932            return;
14933        }
14934
14935        self.change_selections(Default::default(), window, cx, |s| {
14936            s.move_with(|map, selection| {
14937                selection.collapse_to(
14938                    movement::start_of_excerpt(
14939                        map,
14940                        selection.head(),
14941                        workspace::searchable::Direction::Next,
14942                    ),
14943                    SelectionGoal::None,
14944                )
14945            });
14946        })
14947    }
14948
14949    pub fn move_to_end_of_excerpt(
14950        &mut self,
14951        _: &MoveToEndOfExcerpt,
14952        window: &mut Window,
14953        cx: &mut Context<Self>,
14954    ) {
14955        if matches!(self.mode, EditorMode::SingleLine) {
14956            cx.propagate();
14957            return;
14958        }
14959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14960        self.change_selections(Default::default(), window, cx, |s| {
14961            s.move_with(|map, selection| {
14962                selection.collapse_to(
14963                    movement::end_of_excerpt(
14964                        map,
14965                        selection.head(),
14966                        workspace::searchable::Direction::Next,
14967                    ),
14968                    SelectionGoal::None,
14969                )
14970            });
14971        })
14972    }
14973
14974    pub fn move_to_end_of_previous_excerpt(
14975        &mut self,
14976        _: &MoveToEndOfPreviousExcerpt,
14977        window: &mut Window,
14978        cx: &mut Context<Self>,
14979    ) {
14980        if matches!(self.mode, EditorMode::SingleLine) {
14981            cx.propagate();
14982            return;
14983        }
14984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14985        self.change_selections(Default::default(), window, cx, |s| {
14986            s.move_with(|map, selection| {
14987                selection.collapse_to(
14988                    movement::end_of_excerpt(
14989                        map,
14990                        selection.head(),
14991                        workspace::searchable::Direction::Prev,
14992                    ),
14993                    SelectionGoal::None,
14994                )
14995            });
14996        })
14997    }
14998
14999    pub fn select_to_start_of_excerpt(
15000        &mut self,
15001        _: &SelectToStartOfExcerpt,
15002        window: &mut Window,
15003        cx: &mut Context<Self>,
15004    ) {
15005        if matches!(self.mode, EditorMode::SingleLine) {
15006            cx.propagate();
15007            return;
15008        }
15009        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15010        self.change_selections(Default::default(), window, cx, |s| {
15011            s.move_heads_with(|map, head, _| {
15012                (
15013                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15014                    SelectionGoal::None,
15015                )
15016            });
15017        })
15018    }
15019
15020    pub fn select_to_start_of_next_excerpt(
15021        &mut self,
15022        _: &SelectToStartOfNextExcerpt,
15023        window: &mut Window,
15024        cx: &mut Context<Self>,
15025    ) {
15026        if matches!(self.mode, EditorMode::SingleLine) {
15027            cx.propagate();
15028            return;
15029        }
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031        self.change_selections(Default::default(), window, cx, |s| {
15032            s.move_heads_with(|map, head, _| {
15033                (
15034                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15035                    SelectionGoal::None,
15036                )
15037            });
15038        })
15039    }
15040
15041    pub fn select_to_end_of_excerpt(
15042        &mut self,
15043        _: &SelectToEndOfExcerpt,
15044        window: &mut Window,
15045        cx: &mut Context<Self>,
15046    ) {
15047        if matches!(self.mode, EditorMode::SingleLine) {
15048            cx.propagate();
15049            return;
15050        }
15051        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15052        self.change_selections(Default::default(), window, cx, |s| {
15053            s.move_heads_with(|map, head, _| {
15054                (
15055                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15056                    SelectionGoal::None,
15057                )
15058            });
15059        })
15060    }
15061
15062    pub fn select_to_end_of_previous_excerpt(
15063        &mut self,
15064        _: &SelectToEndOfPreviousExcerpt,
15065        window: &mut Window,
15066        cx: &mut Context<Self>,
15067    ) {
15068        if matches!(self.mode, EditorMode::SingleLine) {
15069            cx.propagate();
15070            return;
15071        }
15072        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15073        self.change_selections(Default::default(), window, cx, |s| {
15074            s.move_heads_with(|map, head, _| {
15075                (
15076                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15077                    SelectionGoal::None,
15078                )
15079            });
15080        })
15081    }
15082
15083    pub fn move_to_beginning(
15084        &mut self,
15085        _: &MoveToBeginning,
15086        window: &mut Window,
15087        cx: &mut Context<Self>,
15088    ) {
15089        if matches!(self.mode, EditorMode::SingleLine) {
15090            cx.propagate();
15091            return;
15092        }
15093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15094        self.change_selections(Default::default(), window, cx, |s| {
15095            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
15096        });
15097    }
15098
15099    pub fn select_to_beginning(
15100        &mut self,
15101        _: &SelectToBeginning,
15102        window: &mut Window,
15103        cx: &mut Context<Self>,
15104    ) {
15105        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15106        selection.set_head(Point::zero(), SelectionGoal::None);
15107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15108        self.change_selections(Default::default(), window, cx, |s| {
15109            s.select(vec![selection]);
15110        });
15111    }
15112
15113    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15114        if matches!(self.mode, EditorMode::SingleLine) {
15115            cx.propagate();
15116            return;
15117        }
15118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15119        let cursor = self.buffer.read(cx).read(cx).len();
15120        self.change_selections(Default::default(), window, cx, |s| {
15121            s.select_ranges(vec![cursor..cursor])
15122        });
15123    }
15124
15125    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15126        self.nav_history = nav_history;
15127    }
15128
15129    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15130        self.nav_history.as_ref()
15131    }
15132
15133    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15134        self.push_to_nav_history(
15135            self.selections.newest_anchor().head(),
15136            None,
15137            false,
15138            true,
15139            cx,
15140        );
15141    }
15142
15143    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15144        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15145        let buffer = self.buffer.read(cx).read(cx);
15146        let cursor_position = cursor_anchor.to_point(&buffer);
15147        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15148        let scroll_top_row = scroll_anchor.top_row(&buffer);
15149        drop(buffer);
15150
15151        NavigationData {
15152            cursor_anchor,
15153            cursor_position,
15154            scroll_anchor,
15155            scroll_top_row,
15156        }
15157    }
15158
15159    fn navigation_entry(
15160        &self,
15161        cursor_anchor: Anchor,
15162        cx: &mut Context<Self>,
15163    ) -> Option<NavigationEntry> {
15164        let Some(history) = self.nav_history.clone() else {
15165            return None;
15166        };
15167        let data = self.navigation_data(cursor_anchor, cx);
15168        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15169    }
15170
15171    fn push_to_nav_history(
15172        &mut self,
15173        cursor_anchor: Anchor,
15174        new_position: Option<Point>,
15175        is_deactivate: bool,
15176        always: bool,
15177        cx: &mut Context<Self>,
15178    ) {
15179        let data = self.navigation_data(cursor_anchor, cx);
15180        if let Some(nav_history) = self.nav_history.as_mut() {
15181            if let Some(new_position) = new_position {
15182                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15183                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15184                    return;
15185                }
15186            }
15187
15188            nav_history.push(Some(data), cx);
15189            cx.emit(EditorEvent::PushedToNavHistory {
15190                anchor: cursor_anchor,
15191                is_deactivate,
15192            })
15193        }
15194    }
15195
15196    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15198        let buffer = self.buffer.read(cx).snapshot(cx);
15199        let mut selection = self
15200            .selections
15201            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15202        selection.set_head(buffer.len(), SelectionGoal::None);
15203        self.change_selections(Default::default(), window, cx, |s| {
15204            s.select(vec![selection]);
15205        });
15206    }
15207
15208    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15210        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15211            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
15212        });
15213    }
15214
15215    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15218        let mut selections = self.selections.all::<Point>(&display_map);
15219        let max_point = display_map.buffer_snapshot().max_point();
15220        for selection in &mut selections {
15221            let rows = selection.spanned_rows(true, &display_map);
15222            selection.start = Point::new(rows.start.0, 0);
15223            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15224            selection.reversed = false;
15225        }
15226        self.change_selections(Default::default(), window, cx, |s| {
15227            s.select(selections);
15228        });
15229    }
15230
15231    pub fn split_selection_into_lines(
15232        &mut self,
15233        action: &SplitSelectionIntoLines,
15234        window: &mut Window,
15235        cx: &mut Context<Self>,
15236    ) {
15237        let selections = self
15238            .selections
15239            .all::<Point>(&self.display_snapshot(cx))
15240            .into_iter()
15241            .map(|selection| selection.start..selection.end)
15242            .collect::<Vec<_>>();
15243        self.unfold_ranges(&selections, true, true, cx);
15244
15245        let mut new_selection_ranges = Vec::new();
15246        {
15247            let buffer = self.buffer.read(cx).read(cx);
15248            for selection in selections {
15249                for row in selection.start.row..selection.end.row {
15250                    let line_start = Point::new(row, 0);
15251                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15252
15253                    if action.keep_selections {
15254                        // Keep the selection range for each line
15255                        let selection_start = if row == selection.start.row {
15256                            selection.start
15257                        } else {
15258                            line_start
15259                        };
15260                        new_selection_ranges.push(selection_start..line_end);
15261                    } else {
15262                        // Collapse to cursor at end of line
15263                        new_selection_ranges.push(line_end..line_end);
15264                    }
15265                }
15266
15267                let is_multiline_selection = selection.start.row != selection.end.row;
15268                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15269                // so this action feels more ergonomic when paired with other selection operations
15270                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15271                if !should_skip_last {
15272                    if action.keep_selections {
15273                        if is_multiline_selection {
15274                            let line_start = Point::new(selection.end.row, 0);
15275                            new_selection_ranges.push(line_start..selection.end);
15276                        } else {
15277                            new_selection_ranges.push(selection.start..selection.end);
15278                        }
15279                    } else {
15280                        new_selection_ranges.push(selection.end..selection.end);
15281                    }
15282                }
15283            }
15284        }
15285        self.change_selections(Default::default(), window, cx, |s| {
15286            s.select_ranges(new_selection_ranges);
15287        });
15288    }
15289
15290    pub fn add_selection_above(
15291        &mut self,
15292        action: &AddSelectionAbove,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) {
15296        self.add_selection(true, action.skip_soft_wrap, window, cx);
15297    }
15298
15299    pub fn add_selection_below(
15300        &mut self,
15301        action: &AddSelectionBelow,
15302        window: &mut Window,
15303        cx: &mut Context<Self>,
15304    ) {
15305        self.add_selection(false, action.skip_soft_wrap, window, cx);
15306    }
15307
15308    fn add_selection(
15309        &mut self,
15310        above: bool,
15311        skip_soft_wrap: bool,
15312        window: &mut Window,
15313        cx: &mut Context<Self>,
15314    ) {
15315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15316
15317        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15318        let all_selections = self.selections.all::<Point>(&display_map);
15319        let text_layout_details = self.text_layout_details(window, cx);
15320
15321        let (mut columnar_selections, new_selections_to_columnarize) = {
15322            if let Some(state) = self.add_selections_state.as_ref() {
15323                let columnar_selection_ids: HashSet<_> = state
15324                    .groups
15325                    .iter()
15326                    .flat_map(|group| group.stack.iter())
15327                    .copied()
15328                    .collect();
15329
15330                all_selections
15331                    .into_iter()
15332                    .partition(|s| columnar_selection_ids.contains(&s.id))
15333            } else {
15334                (Vec::new(), all_selections)
15335            }
15336        };
15337
15338        let mut state = self
15339            .add_selections_state
15340            .take()
15341            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15342
15343        for selection in new_selections_to_columnarize {
15344            let range = selection.display_range(&display_map).sorted();
15345            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15346            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15347            let positions = start_x.min(end_x)..start_x.max(end_x);
15348            let mut stack = Vec::new();
15349            for row in range.start.row().0..=range.end.row().0 {
15350                if let Some(selection) = self.selections.build_columnar_selection(
15351                    &display_map,
15352                    DisplayRow(row),
15353                    &positions,
15354                    selection.reversed,
15355                    &text_layout_details,
15356                ) {
15357                    stack.push(selection.id);
15358                    columnar_selections.push(selection);
15359                }
15360            }
15361            if !stack.is_empty() {
15362                if above {
15363                    stack.reverse();
15364                }
15365                state.groups.push(AddSelectionsGroup { above, stack });
15366            }
15367        }
15368
15369        let mut final_selections = Vec::new();
15370        let end_row = if above {
15371            DisplayRow(0)
15372        } else {
15373            display_map.max_point().row()
15374        };
15375
15376        // When `skip_soft_wrap` is true, we use buffer columns instead of pixel
15377        // positions to place new selections, so we need to keep track of the
15378        // column range of the oldest selection in each group, because
15379        // intermediate selections may have been clamped to shorter lines.
15380        // selections may have been clamped to shorter lines.
15381        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15382            let mut map = HashMap::default();
15383            for group in state.groups.iter() {
15384                if let Some(oldest_id) = group.stack.first() {
15385                    if let Some(oldest_selection) =
15386                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15387                    {
15388                        let start_col = oldest_selection.start.column;
15389                        let end_col = oldest_selection.end.column;
15390                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15391                        for id in &group.stack {
15392                            map.insert(*id, goal_columns.clone());
15393                        }
15394                    }
15395                }
15396            }
15397            map
15398        } else {
15399            HashMap::default()
15400        };
15401
15402        let mut last_added_item_per_group = HashMap::default();
15403        for group in state.groups.iter_mut() {
15404            if let Some(last_id) = group.stack.last() {
15405                last_added_item_per_group.insert(*last_id, group);
15406            }
15407        }
15408
15409        for selection in columnar_selections {
15410            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15411                if above == group.above {
15412                    let range = selection.display_range(&display_map).sorted();
15413                    debug_assert_eq!(range.start.row(), range.end.row());
15414                    let row = range.start.row();
15415                    let positions =
15416                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15417                            Pixels::from(start)..Pixels::from(end)
15418                        } else {
15419                            let start_x =
15420                                display_map.x_for_display_point(range.start, &text_layout_details);
15421                            let end_x =
15422                                display_map.x_for_display_point(range.end, &text_layout_details);
15423                            start_x.min(end_x)..start_x.max(end_x)
15424                        };
15425
15426                    let maybe_new_selection = if skip_soft_wrap {
15427                        let goal_columns = goal_columns_by_selection_id
15428                            .remove(&selection.id)
15429                            .unwrap_or_else(|| {
15430                                let start_col = selection.start.column;
15431                                let end_col = selection.end.column;
15432                                start_col.min(end_col)..start_col.max(end_col)
15433                            });
15434                        self.selections.find_next_columnar_selection_by_buffer_row(
15435                            &display_map,
15436                            row,
15437                            end_row,
15438                            above,
15439                            &goal_columns,
15440                            selection.reversed,
15441                            &text_layout_details,
15442                        )
15443                    } else {
15444                        self.selections.find_next_columnar_selection_by_display_row(
15445                            &display_map,
15446                            row,
15447                            end_row,
15448                            above,
15449                            &positions,
15450                            selection.reversed,
15451                            &text_layout_details,
15452                        )
15453                    };
15454
15455                    if let Some(new_selection) = maybe_new_selection {
15456                        group.stack.push(new_selection.id);
15457                        if above {
15458                            final_selections.push(new_selection);
15459                            final_selections.push(selection);
15460                        } else {
15461                            final_selections.push(selection);
15462                            final_selections.push(new_selection);
15463                        }
15464                    } else {
15465                        final_selections.push(selection);
15466                    }
15467                } else {
15468                    group.stack.pop();
15469                }
15470            } else {
15471                final_selections.push(selection);
15472            }
15473        }
15474
15475        self.change_selections(Default::default(), window, cx, |s| {
15476            s.select(final_selections);
15477        });
15478
15479        let final_selection_ids: HashSet<_> = self
15480            .selections
15481            .all::<Point>(&display_map)
15482            .iter()
15483            .map(|s| s.id)
15484            .collect();
15485        state.groups.retain_mut(|group| {
15486            // selections might get merged above so we remove invalid items from stacks
15487            group.stack.retain(|id| final_selection_ids.contains(id));
15488
15489            // single selection in stack can be treated as initial state
15490            group.stack.len() > 1
15491        });
15492
15493        if !state.groups.is_empty() {
15494            self.add_selections_state = Some(state);
15495        }
15496    }
15497
15498    pub fn insert_snippet_at_selections(
15499        &mut self,
15500        action: &InsertSnippet,
15501        window: &mut Window,
15502        cx: &mut Context<Self>,
15503    ) {
15504        self.try_insert_snippet_at_selections(action, window, cx)
15505            .log_err();
15506    }
15507
15508    fn try_insert_snippet_at_selections(
15509        &mut self,
15510        action: &InsertSnippet,
15511        window: &mut Window,
15512        cx: &mut Context<Self>,
15513    ) -> Result<()> {
15514        let insertion_ranges = self
15515            .selections
15516            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15517            .into_iter()
15518            .map(|selection| selection.range())
15519            .collect_vec();
15520
15521        let snippet = if let Some(snippet_body) = &action.snippet {
15522            if action.language.is_none() && action.name.is_none() {
15523                Snippet::parse(snippet_body)?
15524            } else {
15525                bail!("`snippet` is mutually exclusive with `language` and `name`")
15526            }
15527        } else if let Some(name) = &action.name {
15528            let project = self.project().context("no project")?;
15529            let snippet_store = project.read(cx).snippets().read(cx);
15530            let snippet = snippet_store
15531                .snippets_for(action.language.clone(), cx)
15532                .into_iter()
15533                .find(|snippet| snippet.name == *name)
15534                .context("snippet not found")?;
15535            Snippet::parse(&snippet.body)?
15536        } else {
15537            // todo(andrew): open modal to select snippet
15538            bail!("`name` or `snippet` is required")
15539        };
15540
15541        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15542    }
15543
15544    fn select_match_ranges(
15545        &mut self,
15546        range: Range<MultiBufferOffset>,
15547        reversed: bool,
15548        replace_newest: bool,
15549        auto_scroll: Option<Autoscroll>,
15550        window: &mut Window,
15551        cx: &mut Context<Editor>,
15552    ) {
15553        self.unfold_ranges(
15554            std::slice::from_ref(&range),
15555            false,
15556            auto_scroll.is_some(),
15557            cx,
15558        );
15559        let effects = if let Some(scroll) = auto_scroll {
15560            SelectionEffects::scroll(scroll)
15561        } else {
15562            SelectionEffects::no_scroll()
15563        };
15564        self.change_selections(effects, window, cx, |s| {
15565            if replace_newest {
15566                s.delete(s.newest_anchor().id);
15567            }
15568            if reversed {
15569                s.insert_range(range.end..range.start);
15570            } else {
15571                s.insert_range(range);
15572            }
15573        });
15574    }
15575
15576    pub fn select_next_match_internal(
15577        &mut self,
15578        display_map: &DisplaySnapshot,
15579        replace_newest: bool,
15580        autoscroll: Option<Autoscroll>,
15581        window: &mut Window,
15582        cx: &mut Context<Self>,
15583    ) -> Result<()> {
15584        let buffer = display_map.buffer_snapshot();
15585        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15586        if let Some(mut select_next_state) = self.select_next_state.take() {
15587            let query = &select_next_state.query;
15588            if !select_next_state.done {
15589                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15590                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15591                let mut next_selected_range = None;
15592
15593                let bytes_after_last_selection =
15594                    buffer.bytes_in_range(last_selection.end..buffer.len());
15595                let bytes_before_first_selection =
15596                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15597                let query_matches = query
15598                    .stream_find_iter(bytes_after_last_selection)
15599                    .map(|result| (last_selection.end, result))
15600                    .chain(
15601                        query
15602                            .stream_find_iter(bytes_before_first_selection)
15603                            .map(|result| (MultiBufferOffset(0), result)),
15604                    );
15605
15606                for (start_offset, query_match) in query_matches {
15607                    let query_match = query_match.unwrap(); // can only fail due to I/O
15608                    let offset_range =
15609                        start_offset + query_match.start()..start_offset + query_match.end();
15610
15611                    if !select_next_state.wordwise
15612                        || (!buffer.is_inside_word(offset_range.start, None)
15613                            && !buffer.is_inside_word(offset_range.end, None))
15614                    {
15615                        let idx = selections
15616                            .partition_point(|selection| selection.end <= offset_range.start);
15617                        let overlaps = selections
15618                            .get(idx)
15619                            .map_or(false, |selection| selection.start < offset_range.end);
15620
15621                        if !overlaps {
15622                            next_selected_range = Some(offset_range);
15623                            break;
15624                        }
15625                    }
15626                }
15627
15628                if let Some(next_selected_range) = next_selected_range {
15629                    self.select_match_ranges(
15630                        next_selected_range,
15631                        last_selection.reversed,
15632                        replace_newest,
15633                        autoscroll,
15634                        window,
15635                        cx,
15636                    );
15637                } else {
15638                    select_next_state.done = true;
15639                }
15640            }
15641
15642            self.select_next_state = Some(select_next_state);
15643        } else {
15644            let mut only_carets = true;
15645            let mut same_text_selected = true;
15646            let mut selected_text = None;
15647
15648            let mut selections_iter = selections.iter().peekable();
15649            while let Some(selection) = selections_iter.next() {
15650                if selection.start != selection.end {
15651                    only_carets = false;
15652                }
15653
15654                if same_text_selected {
15655                    if selected_text.is_none() {
15656                        selected_text =
15657                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15658                    }
15659
15660                    if let Some(next_selection) = selections_iter.peek() {
15661                        if next_selection.len() == selection.len() {
15662                            let next_selected_text = buffer
15663                                .text_for_range(next_selection.range())
15664                                .collect::<String>();
15665                            if Some(next_selected_text) != selected_text {
15666                                same_text_selected = false;
15667                                selected_text = None;
15668                            }
15669                        } else {
15670                            same_text_selected = false;
15671                            selected_text = None;
15672                        }
15673                    }
15674                }
15675            }
15676
15677            if only_carets {
15678                for selection in &mut selections {
15679                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15680                    selection.start = word_range.start;
15681                    selection.end = word_range.end;
15682                    selection.goal = SelectionGoal::None;
15683                    selection.reversed = false;
15684                    self.select_match_ranges(
15685                        selection.start..selection.end,
15686                        selection.reversed,
15687                        replace_newest,
15688                        autoscroll,
15689                        window,
15690                        cx,
15691                    );
15692                }
15693
15694                if selections.len() == 1 {
15695                    let selection = selections
15696                        .last()
15697                        .expect("ensured that there's only one selection");
15698                    let query = buffer
15699                        .text_for_range(selection.start..selection.end)
15700                        .collect::<String>();
15701                    let is_empty = query.is_empty();
15702                    let select_state = SelectNextState {
15703                        query: self.build_query(&[query], cx)?,
15704                        wordwise: true,
15705                        done: is_empty,
15706                    };
15707                    self.select_next_state = Some(select_state);
15708                } else {
15709                    self.select_next_state = None;
15710                }
15711            } else if let Some(selected_text) = selected_text {
15712                self.select_next_state = Some(SelectNextState {
15713                    query: self.build_query(&[selected_text], cx)?,
15714                    wordwise: false,
15715                    done: false,
15716                });
15717                self.select_next_match_internal(
15718                    display_map,
15719                    replace_newest,
15720                    autoscroll,
15721                    window,
15722                    cx,
15723                )?;
15724            }
15725        }
15726        Ok(())
15727    }
15728
15729    pub fn select_all_matches(
15730        &mut self,
15731        _action: &SelectAllMatches,
15732        window: &mut Window,
15733        cx: &mut Context<Self>,
15734    ) -> Result<()> {
15735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15736
15737        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15738
15739        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15740        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15741        else {
15742            return Ok(());
15743        };
15744
15745        let mut new_selections = Vec::new();
15746
15747        let reversed = self
15748            .selections
15749            .oldest::<MultiBufferOffset>(&display_map)
15750            .reversed;
15751        let buffer = display_map.buffer_snapshot();
15752        let query_matches = select_next_state
15753            .query
15754            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15755
15756        for query_match in query_matches.into_iter() {
15757            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15758            let offset_range = if reversed {
15759                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15760            } else {
15761                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15762            };
15763
15764            if !select_next_state.wordwise
15765                || (!buffer.is_inside_word(offset_range.start, None)
15766                    && !buffer.is_inside_word(offset_range.end, None))
15767            {
15768                new_selections.push(offset_range.start..offset_range.end);
15769            }
15770        }
15771
15772        select_next_state.done = true;
15773
15774        if new_selections.is_empty() {
15775            log::error!("bug: new_selections is empty in select_all_matches");
15776            return Ok(());
15777        }
15778
15779        self.unfold_ranges(&new_selections, false, false, cx);
15780        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15781            selections.select_ranges(new_selections)
15782        });
15783
15784        Ok(())
15785    }
15786
15787    pub fn select_next(
15788        &mut self,
15789        action: &SelectNext,
15790        window: &mut Window,
15791        cx: &mut Context<Self>,
15792    ) -> Result<()> {
15793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15794        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15795        self.select_next_match_internal(
15796            &display_map,
15797            action.replace_newest,
15798            Some(Autoscroll::newest()),
15799            window,
15800            cx,
15801        )
15802    }
15803
15804    pub fn select_previous(
15805        &mut self,
15806        action: &SelectPrevious,
15807        window: &mut Window,
15808        cx: &mut Context<Self>,
15809    ) -> Result<()> {
15810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15811        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15812        let buffer = display_map.buffer_snapshot();
15813        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15814        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15815            let query = &select_prev_state.query;
15816            if !select_prev_state.done {
15817                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15818                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15819                let mut next_selected_range = None;
15820                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15821                let bytes_before_last_selection =
15822                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15823                let bytes_after_first_selection =
15824                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15825                let query_matches = query
15826                    .stream_find_iter(bytes_before_last_selection)
15827                    .map(|result| (last_selection.start, result))
15828                    .chain(
15829                        query
15830                            .stream_find_iter(bytes_after_first_selection)
15831                            .map(|result| (buffer.len(), result)),
15832                    );
15833                for (end_offset, query_match) in query_matches {
15834                    let query_match = query_match.unwrap(); // can only fail due to I/O
15835                    let offset_range =
15836                        end_offset - query_match.end()..end_offset - query_match.start();
15837
15838                    if !select_prev_state.wordwise
15839                        || (!buffer.is_inside_word(offset_range.start, None)
15840                            && !buffer.is_inside_word(offset_range.end, None))
15841                    {
15842                        next_selected_range = Some(offset_range);
15843                        break;
15844                    }
15845                }
15846
15847                if let Some(next_selected_range) = next_selected_range {
15848                    self.select_match_ranges(
15849                        next_selected_range,
15850                        last_selection.reversed,
15851                        action.replace_newest,
15852                        Some(Autoscroll::newest()),
15853                        window,
15854                        cx,
15855                    );
15856                } else {
15857                    select_prev_state.done = true;
15858                }
15859            }
15860
15861            self.select_prev_state = Some(select_prev_state);
15862        } else {
15863            let mut only_carets = true;
15864            let mut same_text_selected = true;
15865            let mut selected_text = None;
15866
15867            let mut selections_iter = selections.iter().peekable();
15868            while let Some(selection) = selections_iter.next() {
15869                if selection.start != selection.end {
15870                    only_carets = false;
15871                }
15872
15873                if same_text_selected {
15874                    if selected_text.is_none() {
15875                        selected_text =
15876                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15877                    }
15878
15879                    if let Some(next_selection) = selections_iter.peek() {
15880                        if next_selection.len() == selection.len() {
15881                            let next_selected_text = buffer
15882                                .text_for_range(next_selection.range())
15883                                .collect::<String>();
15884                            if Some(next_selected_text) != selected_text {
15885                                same_text_selected = false;
15886                                selected_text = None;
15887                            }
15888                        } else {
15889                            same_text_selected = false;
15890                            selected_text = None;
15891                        }
15892                    }
15893                }
15894            }
15895
15896            if only_carets {
15897                for selection in &mut selections {
15898                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15899                    selection.start = word_range.start;
15900                    selection.end = word_range.end;
15901                    selection.goal = SelectionGoal::None;
15902                    selection.reversed = false;
15903                    self.select_match_ranges(
15904                        selection.start..selection.end,
15905                        selection.reversed,
15906                        action.replace_newest,
15907                        Some(Autoscroll::newest()),
15908                        window,
15909                        cx,
15910                    );
15911                }
15912                if selections.len() == 1 {
15913                    let selection = selections
15914                        .last()
15915                        .expect("ensured that there's only one selection");
15916                    let query = buffer
15917                        .text_for_range(selection.start..selection.end)
15918                        .collect::<String>();
15919                    let is_empty = query.is_empty();
15920                    let select_state = SelectNextState {
15921                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15922                        wordwise: true,
15923                        done: is_empty,
15924                    };
15925                    self.select_prev_state = Some(select_state);
15926                } else {
15927                    self.select_prev_state = None;
15928                }
15929            } else if let Some(selected_text) = selected_text {
15930                self.select_prev_state = Some(SelectNextState {
15931                    query: self
15932                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15933                    wordwise: false,
15934                    done: false,
15935                });
15936                self.select_previous(action, window, cx)?;
15937            }
15938        }
15939        Ok(())
15940    }
15941
15942    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15943    /// setting the case sensitivity based on the global
15944    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15945    /// editor's settings.
15946    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15947    where
15948        I: IntoIterator<Item = P>,
15949        P: AsRef<[u8]>,
15950    {
15951        let case_sensitive = self
15952            .select_next_is_case_sensitive
15953            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15954
15955        let mut builder = AhoCorasickBuilder::new();
15956        builder.ascii_case_insensitive(!case_sensitive);
15957        builder.build(patterns)
15958    }
15959
15960    pub fn find_next_match(
15961        &mut self,
15962        _: &FindNextMatch,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) -> Result<()> {
15966        let selections = self.selections.disjoint_anchors_arc();
15967        match selections.first() {
15968            Some(first) if selections.len() >= 2 => {
15969                self.change_selections(Default::default(), window, cx, |s| {
15970                    s.select_ranges([first.range()]);
15971                });
15972            }
15973            _ => self.select_next(
15974                &SelectNext {
15975                    replace_newest: true,
15976                },
15977                window,
15978                cx,
15979            )?,
15980        }
15981        Ok(())
15982    }
15983
15984    pub fn find_previous_match(
15985        &mut self,
15986        _: &FindPreviousMatch,
15987        window: &mut Window,
15988        cx: &mut Context<Self>,
15989    ) -> Result<()> {
15990        let selections = self.selections.disjoint_anchors_arc();
15991        match selections.last() {
15992            Some(last) if selections.len() >= 2 => {
15993                self.change_selections(Default::default(), window, cx, |s| {
15994                    s.select_ranges([last.range()]);
15995                });
15996            }
15997            _ => self.select_previous(
15998                &SelectPrevious {
15999                    replace_newest: true,
16000                },
16001                window,
16002                cx,
16003            )?,
16004        }
16005        Ok(())
16006    }
16007
16008    pub fn toggle_comments(
16009        &mut self,
16010        action: &ToggleComments,
16011        window: &mut Window,
16012        cx: &mut Context<Self>,
16013    ) {
16014        if self.read_only(cx) {
16015            return;
16016        }
16017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16018        let text_layout_details = &self.text_layout_details(window, cx);
16019        self.transact(window, cx, |this, window, cx| {
16020            let mut selections = this
16021                .selections
16022                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16023            let mut edits = Vec::new();
16024            let mut selection_edit_ranges = Vec::new();
16025            let mut last_toggled_row = None;
16026            let snapshot = this.buffer.read(cx).read(cx);
16027            let empty_str: Arc<str> = Arc::default();
16028            let mut suffixes_inserted = Vec::new();
16029            let ignore_indent = action.ignore_indent;
16030
16031            fn comment_prefix_range(
16032                snapshot: &MultiBufferSnapshot,
16033                row: MultiBufferRow,
16034                comment_prefix: &str,
16035                comment_prefix_whitespace: &str,
16036                ignore_indent: bool,
16037            ) -> Range<Point> {
16038                let indent_size = if ignore_indent {
16039                    0
16040                } else {
16041                    snapshot.indent_size_for_line(row).len
16042                };
16043
16044                let start = Point::new(row.0, indent_size);
16045
16046                let mut line_bytes = snapshot
16047                    .bytes_in_range(start..snapshot.max_point())
16048                    .flatten()
16049                    .copied();
16050
16051                // If this line currently begins with the line comment prefix, then record
16052                // the range containing the prefix.
16053                if line_bytes
16054                    .by_ref()
16055                    .take(comment_prefix.len())
16056                    .eq(comment_prefix.bytes())
16057                {
16058                    // Include any whitespace that matches the comment prefix.
16059                    let matching_whitespace_len = line_bytes
16060                        .zip(comment_prefix_whitespace.bytes())
16061                        .take_while(|(a, b)| a == b)
16062                        .count() as u32;
16063                    let end = Point::new(
16064                        start.row,
16065                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16066                    );
16067                    start..end
16068                } else {
16069                    start..start
16070                }
16071            }
16072
16073            fn comment_suffix_range(
16074                snapshot: &MultiBufferSnapshot,
16075                row: MultiBufferRow,
16076                comment_suffix: &str,
16077                comment_suffix_has_leading_space: bool,
16078            ) -> Range<Point> {
16079                let end = Point::new(row.0, snapshot.line_len(row));
16080                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16081
16082                let mut line_end_bytes = snapshot
16083                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16084                    .flatten()
16085                    .copied();
16086
16087                let leading_space_len = if suffix_start_column > 0
16088                    && line_end_bytes.next() == Some(b' ')
16089                    && comment_suffix_has_leading_space
16090                {
16091                    1
16092                } else {
16093                    0
16094                };
16095
16096                // If this line currently begins with the line comment prefix, then record
16097                // the range containing the prefix.
16098                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16099                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16100                    start..end
16101                } else {
16102                    end..end
16103                }
16104            }
16105
16106            // TODO: Handle selections that cross excerpts
16107            for selection in &mut selections {
16108                let start_column = snapshot
16109                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16110                    .len;
16111                let language = if let Some(language) =
16112                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16113                {
16114                    language
16115                } else {
16116                    continue;
16117                };
16118
16119                selection_edit_ranges.clear();
16120
16121                // If multiple selections contain a given row, avoid processing that
16122                // row more than once.
16123                let mut start_row = MultiBufferRow(selection.start.row);
16124                if last_toggled_row == Some(start_row) {
16125                    start_row = start_row.next_row();
16126                }
16127                let end_row =
16128                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16129                        MultiBufferRow(selection.end.row - 1)
16130                    } else {
16131                        MultiBufferRow(selection.end.row)
16132                    };
16133                last_toggled_row = Some(end_row);
16134
16135                if start_row > end_row {
16136                    continue;
16137                }
16138
16139                // If the language has line comments, toggle those.
16140                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16141
16142                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16143                if ignore_indent {
16144                    full_comment_prefixes = full_comment_prefixes
16145                        .into_iter()
16146                        .map(|s| Arc::from(s.trim_end()))
16147                        .collect();
16148                }
16149
16150                if !full_comment_prefixes.is_empty() {
16151                    let first_prefix = full_comment_prefixes
16152                        .first()
16153                        .expect("prefixes is non-empty");
16154                    let prefix_trimmed_lengths = full_comment_prefixes
16155                        .iter()
16156                        .map(|p| p.trim_end_matches(' ').len())
16157                        .collect::<SmallVec<[usize; 4]>>();
16158
16159                    let mut all_selection_lines_are_comments = true;
16160
16161                    for row in start_row.0..=end_row.0 {
16162                        let row = MultiBufferRow(row);
16163                        if start_row < end_row && snapshot.is_line_blank(row) {
16164                            continue;
16165                        }
16166
16167                        let prefix_range = full_comment_prefixes
16168                            .iter()
16169                            .zip(prefix_trimmed_lengths.iter().copied())
16170                            .map(|(prefix, trimmed_prefix_len)| {
16171                                comment_prefix_range(
16172                                    snapshot.deref(),
16173                                    row,
16174                                    &prefix[..trimmed_prefix_len],
16175                                    &prefix[trimmed_prefix_len..],
16176                                    ignore_indent,
16177                                )
16178                            })
16179                            .max_by_key(|range| range.end.column - range.start.column)
16180                            .expect("prefixes is non-empty");
16181
16182                        if prefix_range.is_empty() {
16183                            all_selection_lines_are_comments = false;
16184                        }
16185
16186                        selection_edit_ranges.push(prefix_range);
16187                    }
16188
16189                    if all_selection_lines_are_comments {
16190                        edits.extend(
16191                            selection_edit_ranges
16192                                .iter()
16193                                .cloned()
16194                                .map(|range| (range, empty_str.clone())),
16195                        );
16196                    } else {
16197                        let min_column = selection_edit_ranges
16198                            .iter()
16199                            .map(|range| range.start.column)
16200                            .min()
16201                            .unwrap_or(0);
16202                        edits.extend(selection_edit_ranges.iter().map(|range| {
16203                            let position = Point::new(range.start.row, min_column);
16204                            (position..position, first_prefix.clone())
16205                        }));
16206                    }
16207                } else if let Some(BlockCommentConfig {
16208                    start: full_comment_prefix,
16209                    end: comment_suffix,
16210                    ..
16211                }) = language.block_comment()
16212                {
16213                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16214                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16215                    let prefix_range = comment_prefix_range(
16216                        snapshot.deref(),
16217                        start_row,
16218                        comment_prefix,
16219                        comment_prefix_whitespace,
16220                        ignore_indent,
16221                    );
16222                    let suffix_range = comment_suffix_range(
16223                        snapshot.deref(),
16224                        end_row,
16225                        comment_suffix.trim_start_matches(' '),
16226                        comment_suffix.starts_with(' '),
16227                    );
16228
16229                    if prefix_range.is_empty() || suffix_range.is_empty() {
16230                        edits.push((
16231                            prefix_range.start..prefix_range.start,
16232                            full_comment_prefix.clone(),
16233                        ));
16234                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16235                        suffixes_inserted.push((end_row, comment_suffix.len()));
16236                    } else {
16237                        edits.push((prefix_range, empty_str.clone()));
16238                        edits.push((suffix_range, empty_str.clone()));
16239                    }
16240                } else {
16241                    continue;
16242                }
16243            }
16244
16245            drop(snapshot);
16246            this.buffer.update(cx, |buffer, cx| {
16247                buffer.edit(edits, None, cx);
16248            });
16249
16250            // Adjust selections so that they end before any comment suffixes that
16251            // were inserted.
16252            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16253            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16254            let snapshot = this.buffer.read(cx).read(cx);
16255            for selection in &mut selections {
16256                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16257                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16258                        Ordering::Less => {
16259                            suffixes_inserted.next();
16260                            continue;
16261                        }
16262                        Ordering::Greater => break,
16263                        Ordering::Equal => {
16264                            if selection.end.column == snapshot.line_len(row) {
16265                                if selection.is_empty() {
16266                                    selection.start.column -= suffix_len as u32;
16267                                }
16268                                selection.end.column -= suffix_len as u32;
16269                            }
16270                            break;
16271                        }
16272                    }
16273                }
16274            }
16275
16276            drop(snapshot);
16277            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16278
16279            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16280            let selections_on_single_row = selections.windows(2).all(|selections| {
16281                selections[0].start.row == selections[1].start.row
16282                    && selections[0].end.row == selections[1].end.row
16283                    && selections[0].start.row == selections[0].end.row
16284            });
16285            let selections_selecting = selections
16286                .iter()
16287                .any(|selection| selection.start != selection.end);
16288            let advance_downwards = action.advance_downwards
16289                && selections_on_single_row
16290                && !selections_selecting
16291                && !matches!(this.mode, EditorMode::SingleLine);
16292
16293            if advance_downwards {
16294                let snapshot = this.buffer.read(cx).snapshot(cx);
16295
16296                this.change_selections(Default::default(), window, cx, |s| {
16297                    s.move_cursors_with(|display_snapshot, display_point, _| {
16298                        let mut point = display_point.to_point(display_snapshot);
16299                        point.row += 1;
16300                        point = snapshot.clip_point(point, Bias::Left);
16301                        let display_point = point.to_display_point(display_snapshot);
16302                        let goal = SelectionGoal::HorizontalPosition(
16303                            display_snapshot
16304                                .x_for_display_point(display_point, text_layout_details)
16305                                .into(),
16306                        );
16307                        (display_point, goal)
16308                    })
16309                });
16310            }
16311        });
16312    }
16313
16314    pub fn select_enclosing_symbol(
16315        &mut self,
16316        _: &SelectEnclosingSymbol,
16317        window: &mut Window,
16318        cx: &mut Context<Self>,
16319    ) {
16320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16321
16322        let buffer = self.buffer.read(cx).snapshot(cx);
16323        let old_selections = self
16324            .selections
16325            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16326            .into_boxed_slice();
16327
16328        fn update_selection(
16329            selection: &Selection<MultiBufferOffset>,
16330            buffer_snap: &MultiBufferSnapshot,
16331        ) -> Option<Selection<MultiBufferOffset>> {
16332            let cursor = selection.head();
16333            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16334            for symbol in symbols.iter().rev() {
16335                let start = symbol.range.start.to_offset(buffer_snap);
16336                let end = symbol.range.end.to_offset(buffer_snap);
16337                let new_range = start..end;
16338                if start < selection.start || end > selection.end {
16339                    return Some(Selection {
16340                        id: selection.id,
16341                        start: new_range.start,
16342                        end: new_range.end,
16343                        goal: SelectionGoal::None,
16344                        reversed: selection.reversed,
16345                    });
16346                }
16347            }
16348            None
16349        }
16350
16351        let mut selected_larger_symbol = false;
16352        let new_selections = old_selections
16353            .iter()
16354            .map(|selection| match update_selection(selection, &buffer) {
16355                Some(new_selection) => {
16356                    if new_selection.range() != selection.range() {
16357                        selected_larger_symbol = true;
16358                    }
16359                    new_selection
16360                }
16361                None => selection.clone(),
16362            })
16363            .collect::<Vec<_>>();
16364
16365        if selected_larger_symbol {
16366            self.change_selections(Default::default(), window, cx, |s| {
16367                s.select(new_selections);
16368            });
16369        }
16370    }
16371
16372    pub fn select_larger_syntax_node(
16373        &mut self,
16374        _: &SelectLargerSyntaxNode,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) {
16378        let Some(visible_row_count) = self.visible_row_count() else {
16379            return;
16380        };
16381        let old_selections: Box<[_]> = self
16382            .selections
16383            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16384            .into();
16385        if old_selections.is_empty() {
16386            return;
16387        }
16388
16389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16390
16391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16392        let buffer = self.buffer.read(cx).snapshot(cx);
16393
16394        let mut selected_larger_node = false;
16395        let mut new_selections = old_selections
16396            .iter()
16397            .map(|selection| {
16398                let old_range = selection.start..selection.end;
16399
16400                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16401                    // manually select word at selection
16402                    if ["string_content", "inline"].contains(&node.kind()) {
16403                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16404                        // ignore if word is already selected
16405                        if !word_range.is_empty() && old_range != word_range {
16406                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16407                            // only select word if start and end point belongs to same word
16408                            if word_range == last_word_range {
16409                                selected_larger_node = true;
16410                                return Selection {
16411                                    id: selection.id,
16412                                    start: word_range.start,
16413                                    end: word_range.end,
16414                                    goal: SelectionGoal::None,
16415                                    reversed: selection.reversed,
16416                                };
16417                            }
16418                        }
16419                    }
16420                }
16421
16422                let mut new_range = old_range.clone();
16423                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16424                    new_range = range;
16425                    if !node.is_named() {
16426                        continue;
16427                    }
16428                    if !display_map.intersects_fold(new_range.start)
16429                        && !display_map.intersects_fold(new_range.end)
16430                    {
16431                        break;
16432                    }
16433                }
16434
16435                selected_larger_node |= new_range != old_range;
16436                Selection {
16437                    id: selection.id,
16438                    start: new_range.start,
16439                    end: new_range.end,
16440                    goal: SelectionGoal::None,
16441                    reversed: selection.reversed,
16442                }
16443            })
16444            .collect::<Vec<_>>();
16445
16446        if !selected_larger_node {
16447            return; // don't put this call in the history
16448        }
16449
16450        // scroll based on transformation done to the last selection created by the user
16451        let (last_old, last_new) = old_selections
16452            .last()
16453            .zip(new_selections.last().cloned())
16454            .expect("old_selections isn't empty");
16455
16456        // revert selection
16457        let is_selection_reversed = {
16458            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16459            new_selections.last_mut().expect("checked above").reversed =
16460                should_newest_selection_be_reversed;
16461            should_newest_selection_be_reversed
16462        };
16463
16464        if selected_larger_node {
16465            self.select_syntax_node_history.disable_clearing = true;
16466            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16467                s.select(new_selections.clone());
16468            });
16469            self.select_syntax_node_history.disable_clearing = false;
16470        }
16471
16472        let start_row = last_new.start.to_display_point(&display_map).row().0;
16473        let end_row = last_new.end.to_display_point(&display_map).row().0;
16474        let selection_height = end_row - start_row + 1;
16475        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16476
16477        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16478        let scroll_behavior = if fits_on_the_screen {
16479            self.request_autoscroll(Autoscroll::fit(), cx);
16480            SelectSyntaxNodeScrollBehavior::FitSelection
16481        } else if is_selection_reversed {
16482            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16483            SelectSyntaxNodeScrollBehavior::CursorTop
16484        } else {
16485            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16486            SelectSyntaxNodeScrollBehavior::CursorBottom
16487        };
16488
16489        self.select_syntax_node_history.push((
16490            old_selections,
16491            scroll_behavior,
16492            is_selection_reversed,
16493        ));
16494    }
16495
16496    pub fn select_smaller_syntax_node(
16497        &mut self,
16498        _: &SelectSmallerSyntaxNode,
16499        window: &mut Window,
16500        cx: &mut Context<Self>,
16501    ) {
16502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16503
16504        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16505            self.select_syntax_node_history.pop()
16506        {
16507            if let Some(selection) = selections.last_mut() {
16508                selection.reversed = is_selection_reversed;
16509            }
16510
16511            self.select_syntax_node_history.disable_clearing = true;
16512            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16513                s.select(selections.to_vec());
16514            });
16515            self.select_syntax_node_history.disable_clearing = false;
16516
16517            match scroll_behavior {
16518                SelectSyntaxNodeScrollBehavior::CursorTop => {
16519                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16520                }
16521                SelectSyntaxNodeScrollBehavior::FitSelection => {
16522                    self.request_autoscroll(Autoscroll::fit(), cx);
16523                }
16524                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16525                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16526                }
16527            }
16528        }
16529    }
16530
16531    pub fn unwrap_syntax_node(
16532        &mut self,
16533        _: &UnwrapSyntaxNode,
16534        window: &mut Window,
16535        cx: &mut Context<Self>,
16536    ) {
16537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16538
16539        let buffer = self.buffer.read(cx).snapshot(cx);
16540        let selections = self
16541            .selections
16542            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16543            .into_iter()
16544            // subtracting the offset requires sorting
16545            .sorted_by_key(|i| i.start);
16546
16547        let full_edits = selections
16548            .into_iter()
16549            .filter_map(|selection| {
16550                let child = if selection.is_empty()
16551                    && let Some((_, ancestor_range)) =
16552                        buffer.syntax_ancestor(selection.start..selection.end)
16553                {
16554                    ancestor_range
16555                } else {
16556                    selection.range()
16557                };
16558
16559                let mut parent = child.clone();
16560                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16561                    parent = ancestor_range;
16562                    if parent.start < child.start || parent.end > child.end {
16563                        break;
16564                    }
16565                }
16566
16567                if parent == child {
16568                    return None;
16569                }
16570                let text = buffer.text_for_range(child).collect::<String>();
16571                Some((selection.id, parent, text))
16572            })
16573            .collect::<Vec<_>>();
16574        if full_edits.is_empty() {
16575            return;
16576        }
16577
16578        self.transact(window, cx, |this, window, cx| {
16579            this.buffer.update(cx, |buffer, cx| {
16580                buffer.edit(
16581                    full_edits
16582                        .iter()
16583                        .map(|(_, p, t)| (p.clone(), t.clone()))
16584                        .collect::<Vec<_>>(),
16585                    None,
16586                    cx,
16587                );
16588            });
16589            this.change_selections(Default::default(), window, cx, |s| {
16590                let mut offset = 0;
16591                let mut selections = vec![];
16592                for (id, parent, text) in full_edits {
16593                    let start = parent.start - offset;
16594                    offset += (parent.end - parent.start) - text.len();
16595                    selections.push(Selection {
16596                        id,
16597                        start,
16598                        end: start + text.len(),
16599                        reversed: false,
16600                        goal: Default::default(),
16601                    });
16602                }
16603                s.select(selections);
16604            });
16605        });
16606    }
16607
16608    pub fn select_next_syntax_node(
16609        &mut self,
16610        _: &SelectNextSyntaxNode,
16611        window: &mut Window,
16612        cx: &mut Context<Self>,
16613    ) {
16614        let old_selections: Box<[_]> = self
16615            .selections
16616            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16617            .into();
16618        if old_selections.is_empty() {
16619            return;
16620        }
16621
16622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16623
16624        let buffer = self.buffer.read(cx).snapshot(cx);
16625        let mut selected_sibling = false;
16626
16627        let new_selections = old_selections
16628            .iter()
16629            .map(|selection| {
16630                let old_range = selection.start..selection.end;
16631
16632                let old_range =
16633                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16634                let excerpt = buffer.excerpt_containing(old_range.clone());
16635
16636                if let Some(mut excerpt) = excerpt
16637                    && let Some(node) = excerpt
16638                        .buffer()
16639                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16640                {
16641                    let new_range = excerpt.map_range_from_buffer(
16642                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16643                    );
16644                    selected_sibling = true;
16645                    Selection {
16646                        id: selection.id,
16647                        start: new_range.start,
16648                        end: new_range.end,
16649                        goal: SelectionGoal::None,
16650                        reversed: selection.reversed,
16651                    }
16652                } else {
16653                    selection.clone()
16654                }
16655            })
16656            .collect::<Vec<_>>();
16657
16658        if selected_sibling {
16659            self.change_selections(
16660                SelectionEffects::scroll(Autoscroll::fit()),
16661                window,
16662                cx,
16663                |s| {
16664                    s.select(new_selections);
16665                },
16666            );
16667        }
16668    }
16669
16670    pub fn select_prev_syntax_node(
16671        &mut self,
16672        _: &SelectPreviousSyntaxNode,
16673        window: &mut Window,
16674        cx: &mut Context<Self>,
16675    ) {
16676        let old_selections: Box<[_]> = self
16677            .selections
16678            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16679            .into();
16680        if old_selections.is_empty() {
16681            return;
16682        }
16683
16684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16685
16686        let buffer = self.buffer.read(cx).snapshot(cx);
16687        let mut selected_sibling = false;
16688
16689        let new_selections = old_selections
16690            .iter()
16691            .map(|selection| {
16692                let old_range = selection.start..selection.end;
16693                let old_range =
16694                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16695                let excerpt = buffer.excerpt_containing(old_range.clone());
16696
16697                if let Some(mut excerpt) = excerpt
16698                    && let Some(node) = excerpt
16699                        .buffer()
16700                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16701                {
16702                    let new_range = excerpt.map_range_from_buffer(
16703                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16704                    );
16705                    selected_sibling = true;
16706                    Selection {
16707                        id: selection.id,
16708                        start: new_range.start,
16709                        end: new_range.end,
16710                        goal: SelectionGoal::None,
16711                        reversed: selection.reversed,
16712                    }
16713                } else {
16714                    selection.clone()
16715                }
16716            })
16717            .collect::<Vec<_>>();
16718
16719        if selected_sibling {
16720            self.change_selections(
16721                SelectionEffects::scroll(Autoscroll::fit()),
16722                window,
16723                cx,
16724                |s| {
16725                    s.select(new_selections);
16726                },
16727            );
16728        }
16729    }
16730
16731    pub fn move_to_start_of_larger_syntax_node(
16732        &mut self,
16733        _: &MoveToStartOfLargerSyntaxNode,
16734        window: &mut Window,
16735        cx: &mut Context<Self>,
16736    ) {
16737        self.move_cursors_to_syntax_nodes(window, cx, false);
16738    }
16739
16740    pub fn move_to_end_of_larger_syntax_node(
16741        &mut self,
16742        _: &MoveToEndOfLargerSyntaxNode,
16743        window: &mut Window,
16744        cx: &mut Context<Self>,
16745    ) {
16746        self.move_cursors_to_syntax_nodes(window, cx, true);
16747    }
16748
16749    fn find_syntax_node_boundary(
16750        &self,
16751        selection_pos: MultiBufferOffset,
16752        move_to_end: bool,
16753        display_map: &DisplaySnapshot,
16754        buffer: &MultiBufferSnapshot,
16755    ) -> MultiBufferOffset {
16756        let old_range = selection_pos..selection_pos;
16757        let mut new_pos = selection_pos;
16758        let mut search_range = old_range;
16759        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
16760            search_range = range.clone();
16761            if !node.is_named()
16762                || display_map.intersects_fold(range.start)
16763                || display_map.intersects_fold(range.end)
16764                // If cursor is already at the end of the syntax node, continue searching
16765                || (move_to_end && range.end == selection_pos)
16766                // If cursor is already at the start of the syntax node, continue searching
16767                || (!move_to_end && range.start == selection_pos)
16768            {
16769                continue;
16770            }
16771
16772            // If we found a string_content node, find the largest parent that is still string_content
16773            // Enables us to skip to the end of strings without taking multiple steps inside the string
16774            let (_, final_range) = if node.kind() == "string_content" {
16775                let mut current_node = node;
16776                let mut current_range = range;
16777                while let Some((parent, parent_range)) =
16778                    buffer.syntax_ancestor(current_range.clone())
16779                {
16780                    if parent.kind() == "string_content" {
16781                        current_node = parent;
16782                        current_range = parent_range;
16783                    } else {
16784                        break;
16785                    }
16786                }
16787
16788                (current_node, current_range)
16789            } else {
16790                (node, range)
16791            };
16792
16793            new_pos = if move_to_end {
16794                final_range.end
16795            } else {
16796                final_range.start
16797            };
16798
16799            break;
16800        }
16801
16802        new_pos
16803    }
16804
16805    fn move_cursors_to_syntax_nodes(
16806        &mut self,
16807        window: &mut Window,
16808        cx: &mut Context<Self>,
16809        move_to_end: bool,
16810    ) -> bool {
16811        let old_selections: Box<[_]> = self
16812            .selections
16813            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16814            .into();
16815        if old_selections.is_empty() {
16816            return false;
16817        }
16818
16819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16820
16821        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16822        let buffer = self.buffer.read(cx).snapshot(cx);
16823
16824        let mut any_cursor_moved = false;
16825        let new_selections = old_selections
16826            .iter()
16827            .map(|selection| {
16828                if !selection.is_empty() {
16829                    return selection.clone();
16830                }
16831
16832                let selection_pos = selection.head();
16833                let new_pos = self.find_syntax_node_boundary(
16834                    selection_pos,
16835                    move_to_end,
16836                    &display_map,
16837                    &buffer,
16838                );
16839
16840                any_cursor_moved |= new_pos != selection_pos;
16841
16842                Selection {
16843                    id: selection.id,
16844                    start: new_pos,
16845                    end: new_pos,
16846                    goal: SelectionGoal::None,
16847                    reversed: false,
16848                }
16849            })
16850            .collect::<Vec<_>>();
16851
16852        self.change_selections(Default::default(), window, cx, |s| {
16853            s.select(new_selections);
16854        });
16855        self.request_autoscroll(Autoscroll::newest(), cx);
16856
16857        any_cursor_moved
16858    }
16859
16860    pub fn select_to_start_of_larger_syntax_node(
16861        &mut self,
16862        _: &SelectToStartOfLargerSyntaxNode,
16863        window: &mut Window,
16864        cx: &mut Context<Self>,
16865    ) {
16866        self.select_to_syntax_nodes(window, cx, false);
16867    }
16868
16869    pub fn select_to_end_of_larger_syntax_node(
16870        &mut self,
16871        _: &SelectToEndOfLargerSyntaxNode,
16872        window: &mut Window,
16873        cx: &mut Context<Self>,
16874    ) {
16875        self.select_to_syntax_nodes(window, cx, true);
16876    }
16877
16878    fn select_to_syntax_nodes(
16879        &mut self,
16880        window: &mut Window,
16881        cx: &mut Context<Self>,
16882        move_to_end: bool,
16883    ) {
16884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16885
16886        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16887        let buffer = self.buffer.read(cx).snapshot(cx);
16888        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
16889
16890        let new_selections = old_selections
16891            .iter()
16892            .map(|selection| {
16893                let new_pos = self.find_syntax_node_boundary(
16894                    selection.head(),
16895                    move_to_end,
16896                    &display_map,
16897                    &buffer,
16898                );
16899
16900                let mut new_selection = selection.clone();
16901                new_selection.set_head(new_pos, SelectionGoal::None);
16902                new_selection
16903            })
16904            .collect::<Vec<_>>();
16905
16906        self.change_selections(Default::default(), window, cx, |s| {
16907            s.select(new_selections);
16908        });
16909    }
16910
16911    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16912        if !EditorSettings::get_global(cx).gutter.runnables || !self.enable_runnables {
16913            self.clear_tasks();
16914            return Task::ready(());
16915        }
16916        let project = self.project().map(Entity::downgrade);
16917        let task_sources = self.lsp_task_sources(cx);
16918        let multi_buffer = self.buffer.downgrade();
16919        cx.spawn_in(window, async move |editor, cx| {
16920            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16921            let Some(project) = project.and_then(|p| p.upgrade()) else {
16922                return;
16923            };
16924            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16925                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16926            }) else {
16927                return;
16928            };
16929
16930            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16931            if hide_runnables {
16932                return;
16933            }
16934            let new_rows =
16935                cx.background_spawn({
16936                    let snapshot = display_snapshot.clone();
16937                    async move {
16938                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16939                    }
16940                })
16941                    .await;
16942            let Ok(lsp_tasks) =
16943                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16944            else {
16945                return;
16946            };
16947            let lsp_tasks = lsp_tasks.await;
16948
16949            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16950                lsp_tasks
16951                    .into_iter()
16952                    .flat_map(|(kind, tasks)| {
16953                        tasks.into_iter().filter_map(move |(location, task)| {
16954                            Some((kind.clone(), location?, task))
16955                        })
16956                    })
16957                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16958                        let buffer = location.target.buffer;
16959                        let buffer_snapshot = buffer.read(cx).snapshot();
16960                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16961                            |(excerpt_id, snapshot, _)| {
16962                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16963                                    display_snapshot
16964                                        .buffer_snapshot()
16965                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16966                                } else {
16967                                    None
16968                                }
16969                            },
16970                        );
16971                        if let Some(offset) = offset {
16972                            let task_buffer_range =
16973                                location.target.range.to_point(&buffer_snapshot);
16974                            let context_buffer_range =
16975                                task_buffer_range.to_offset(&buffer_snapshot);
16976                            let context_range = BufferOffset(context_buffer_range.start)
16977                                ..BufferOffset(context_buffer_range.end);
16978
16979                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16980                                .or_insert_with(|| RunnableTasks {
16981                                    templates: Vec::new(),
16982                                    offset,
16983                                    column: task_buffer_range.start.column,
16984                                    extra_variables: HashMap::default(),
16985                                    context_range,
16986                                })
16987                                .templates
16988                                .push((kind, task.original_task().clone()));
16989                        }
16990
16991                        acc
16992                    })
16993            }) else {
16994                return;
16995            };
16996
16997            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16998                buffer.language_settings(cx).tasks.prefer_lsp
16999            }) else {
17000                return;
17001            };
17002
17003            let rows = Self::runnable_rows(
17004                project,
17005                display_snapshot,
17006                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
17007                new_rows,
17008                cx.clone(),
17009            )
17010            .await;
17011            editor
17012                .update(cx, |editor, _| {
17013                    editor.clear_tasks();
17014                    for (key, mut value) in rows {
17015                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
17016                            value.templates.extend(lsp_tasks.templates);
17017                        }
17018
17019                        editor.insert_tasks(key, value);
17020                    }
17021                    for (key, value) in lsp_tasks_by_rows {
17022                        editor.insert_tasks(key, value);
17023                    }
17024                })
17025                .ok();
17026        })
17027    }
17028    fn fetch_runnable_ranges(
17029        snapshot: &DisplaySnapshot,
17030        range: Range<Anchor>,
17031    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
17032        snapshot.buffer_snapshot().runnable_ranges(range).collect()
17033    }
17034
17035    fn runnable_rows(
17036        project: Entity<Project>,
17037        snapshot: DisplaySnapshot,
17038        prefer_lsp: bool,
17039        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
17040        cx: AsyncWindowContext,
17041    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
17042        cx.spawn(async move |cx| {
17043            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
17044            for (run_range, mut runnable) in runnable_ranges {
17045                let Some(tasks) = cx
17046                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
17047                    .ok()
17048                else {
17049                    continue;
17050                };
17051                let mut tasks = tasks.await;
17052
17053                if prefer_lsp {
17054                    tasks.retain(|(task_kind, _)| {
17055                        !matches!(task_kind, TaskSourceKind::Language { .. })
17056                    });
17057                }
17058                if tasks.is_empty() {
17059                    continue;
17060                }
17061
17062                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
17063                let Some(row) = snapshot
17064                    .buffer_snapshot()
17065                    .buffer_line_for_row(MultiBufferRow(point.row))
17066                    .map(|(_, range)| range.start.row)
17067                else {
17068                    continue;
17069                };
17070
17071                let context_range =
17072                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
17073                runnable_rows.push((
17074                    (runnable.buffer_id, row),
17075                    RunnableTasks {
17076                        templates: tasks,
17077                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
17078                        context_range,
17079                        column: point.column,
17080                        extra_variables: runnable.extra_captures,
17081                    },
17082                ));
17083            }
17084            runnable_rows
17085        })
17086    }
17087
17088    fn templates_with_tags(
17089        project: &Entity<Project>,
17090        runnable: &mut Runnable,
17091        cx: &mut App,
17092    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
17093        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
17094            let (worktree_id, file) = project
17095                .buffer_for_id(runnable.buffer, cx)
17096                .and_then(|buffer| buffer.read(cx).file())
17097                .map(|file| (file.worktree_id(cx), file.clone()))
17098                .unzip();
17099
17100            (
17101                project.task_store().read(cx).task_inventory().cloned(),
17102                worktree_id,
17103                file,
17104            )
17105        });
17106
17107        let tags = mem::take(&mut runnable.tags);
17108        let language = runnable.language.clone();
17109        cx.spawn(async move |cx| {
17110            let mut templates_with_tags = Vec::new();
17111            if let Some(inventory) = inventory {
17112                for RunnableTag(tag) in tags {
17113                    let new_tasks = inventory.update(cx, |inventory, cx| {
17114                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
17115                    });
17116                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
17117                        move |(_, template)| {
17118                            template.tags.iter().any(|source_tag| source_tag == &tag)
17119                        },
17120                    ));
17121                }
17122            }
17123            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
17124
17125            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
17126                // Strongest source wins; if we have worktree tag binding, prefer that to
17127                // global and language bindings;
17128                // if we have a global binding, prefer that to language binding.
17129                let first_mismatch = templates_with_tags
17130                    .iter()
17131                    .position(|(tag_source, _)| tag_source != leading_tag_source);
17132                if let Some(index) = first_mismatch {
17133                    templates_with_tags.truncate(index);
17134                }
17135            }
17136
17137            templates_with_tags
17138        })
17139    }
17140
17141    pub fn move_to_enclosing_bracket(
17142        &mut self,
17143        _: &MoveToEnclosingBracket,
17144        window: &mut Window,
17145        cx: &mut Context<Self>,
17146    ) {
17147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17148        self.change_selections(Default::default(), window, cx, |s| {
17149            s.move_offsets_with(|snapshot, selection| {
17150                let Some(enclosing_bracket_ranges) =
17151                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17152                else {
17153                    return;
17154                };
17155
17156                let mut best_length = usize::MAX;
17157                let mut best_inside = false;
17158                let mut best_in_bracket_range = false;
17159                let mut best_destination = None;
17160                for (open, close) in enclosing_bracket_ranges {
17161                    let close = close.to_inclusive();
17162                    let length = *close.end() - open.start;
17163                    let inside = selection.start >= open.end && selection.end <= *close.start();
17164                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17165                        || close.contains(&selection.head());
17166
17167                    // If best is next to a bracket and current isn't, skip
17168                    if !in_bracket_range && best_in_bracket_range {
17169                        continue;
17170                    }
17171
17172                    // Prefer smaller lengths unless best is inside and current isn't
17173                    if length > best_length && (best_inside || !inside) {
17174                        continue;
17175                    }
17176
17177                    best_length = length;
17178                    best_inside = inside;
17179                    best_in_bracket_range = in_bracket_range;
17180                    best_destination = Some(
17181                        if close.contains(&selection.start) && close.contains(&selection.end) {
17182                            if inside { open.end } else { open.start }
17183                        } else if inside {
17184                            *close.start()
17185                        } else {
17186                            *close.end()
17187                        },
17188                    );
17189                }
17190
17191                if let Some(destination) = best_destination {
17192                    selection.collapse_to(destination, SelectionGoal::None);
17193                }
17194            })
17195        });
17196    }
17197
17198    pub fn undo_selection(
17199        &mut self,
17200        _: &UndoSelection,
17201        window: &mut Window,
17202        cx: &mut Context<Self>,
17203    ) {
17204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17205        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17206            self.selection_history.mode = SelectionHistoryMode::Undoing;
17207            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17208                this.end_selection(window, cx);
17209                this.change_selections(
17210                    SelectionEffects::scroll(Autoscroll::newest()),
17211                    window,
17212                    cx,
17213                    |s| s.select_anchors(entry.selections.to_vec()),
17214                );
17215            });
17216            self.selection_history.mode = SelectionHistoryMode::Normal;
17217
17218            self.select_next_state = entry.select_next_state;
17219            self.select_prev_state = entry.select_prev_state;
17220            self.add_selections_state = entry.add_selections_state;
17221        }
17222    }
17223
17224    pub fn redo_selection(
17225        &mut self,
17226        _: &RedoSelection,
17227        window: &mut Window,
17228        cx: &mut Context<Self>,
17229    ) {
17230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17231        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17232            self.selection_history.mode = SelectionHistoryMode::Redoing;
17233            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17234                this.end_selection(window, cx);
17235                this.change_selections(
17236                    SelectionEffects::scroll(Autoscroll::newest()),
17237                    window,
17238                    cx,
17239                    |s| s.select_anchors(entry.selections.to_vec()),
17240                );
17241            });
17242            self.selection_history.mode = SelectionHistoryMode::Normal;
17243
17244            self.select_next_state = entry.select_next_state;
17245            self.select_prev_state = entry.select_prev_state;
17246            self.add_selections_state = entry.add_selections_state;
17247        }
17248    }
17249
17250    pub fn expand_excerpts(
17251        &mut self,
17252        action: &ExpandExcerpts,
17253        _: &mut Window,
17254        cx: &mut Context<Self>,
17255    ) {
17256        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17257    }
17258
17259    pub fn expand_excerpts_down(
17260        &mut self,
17261        action: &ExpandExcerptsDown,
17262        _: &mut Window,
17263        cx: &mut Context<Self>,
17264    ) {
17265        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17266    }
17267
17268    pub fn expand_excerpts_up(
17269        &mut self,
17270        action: &ExpandExcerptsUp,
17271        _: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) {
17274        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17275    }
17276
17277    pub fn expand_excerpts_for_direction(
17278        &mut self,
17279        lines: u32,
17280        direction: ExpandExcerptDirection,
17281        cx: &mut Context<Self>,
17282    ) {
17283        let selections = self.selections.disjoint_anchors_arc();
17284
17285        let lines = if lines == 0 {
17286            EditorSettings::get_global(cx).expand_excerpt_lines
17287        } else {
17288            lines
17289        };
17290
17291        let snapshot = self.buffer.read(cx).snapshot(cx);
17292        let mut excerpt_ids = selections
17293            .iter()
17294            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
17295            .collect::<Vec<_>>();
17296        excerpt_ids.sort();
17297        excerpt_ids.dedup();
17298
17299        if self.delegate_expand_excerpts {
17300            cx.emit(EditorEvent::ExpandExcerptsRequested {
17301                excerpt_ids,
17302                lines,
17303                direction,
17304            });
17305            return;
17306        }
17307
17308        self.buffer.update(cx, |buffer, cx| {
17309            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
17310        })
17311    }
17312
17313    pub fn expand_excerpt(
17314        &mut self,
17315        excerpt: ExcerptId,
17316        direction: ExpandExcerptDirection,
17317        window: &mut Window,
17318        cx: &mut Context<Self>,
17319    ) {
17320        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17321
17322        if self.delegate_expand_excerpts {
17323            cx.emit(EditorEvent::ExpandExcerptsRequested {
17324                excerpt_ids: vec![excerpt],
17325                lines: lines_to_expand,
17326                direction,
17327            });
17328            return;
17329        }
17330
17331        let current_scroll_position = self.scroll_position(cx);
17332        let mut scroll = None;
17333
17334        if direction == ExpandExcerptDirection::Down {
17335            let multi_buffer = self.buffer.read(cx);
17336            let snapshot = multi_buffer.snapshot(cx);
17337            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
17338                && let Some(buffer) = multi_buffer.buffer(buffer_id)
17339                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
17340            {
17341                let buffer_snapshot = buffer.read(cx).snapshot();
17342                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
17343                let last_row = buffer_snapshot.max_point().row;
17344                let lines_below = last_row.saturating_sub(excerpt_end_row);
17345                if lines_below >= lines_to_expand {
17346                    scroll = Some(
17347                        current_scroll_position
17348                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17349                    );
17350                }
17351            }
17352        }
17353        if direction == ExpandExcerptDirection::Up
17354            && self
17355                .buffer
17356                .read(cx)
17357                .snapshot(cx)
17358                .excerpt_before(excerpt)
17359                .is_none()
17360        {
17361            scroll = Some(current_scroll_position);
17362        }
17363
17364        self.buffer.update(cx, |buffer, cx| {
17365            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
17366        });
17367
17368        if let Some(new_scroll_position) = scroll {
17369            self.set_scroll_position(new_scroll_position, window, cx);
17370        }
17371    }
17372
17373    pub fn go_to_singleton_buffer_point(
17374        &mut self,
17375        point: Point,
17376        window: &mut Window,
17377        cx: &mut Context<Self>,
17378    ) {
17379        self.go_to_singleton_buffer_range(point..point, window, cx);
17380    }
17381
17382    pub fn go_to_singleton_buffer_range(
17383        &mut self,
17384        range: Range<Point>,
17385        window: &mut Window,
17386        cx: &mut Context<Self>,
17387    ) {
17388        let multibuffer = self.buffer().read(cx);
17389        let Some(buffer) = multibuffer.as_singleton() else {
17390            return;
17391        };
17392        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
17393            return;
17394        };
17395        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
17396            return;
17397        };
17398        self.change_selections(
17399            SelectionEffects::default().nav_history(true),
17400            window,
17401            cx,
17402            |s| s.select_anchor_ranges([start..end]),
17403        );
17404    }
17405
17406    pub fn go_to_diagnostic(
17407        &mut self,
17408        action: &GoToDiagnostic,
17409        window: &mut Window,
17410        cx: &mut Context<Self>,
17411    ) {
17412        if !self.diagnostics_enabled() {
17413            return;
17414        }
17415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17416        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17417    }
17418
17419    pub fn go_to_prev_diagnostic(
17420        &mut self,
17421        action: &GoToPreviousDiagnostic,
17422        window: &mut Window,
17423        cx: &mut Context<Self>,
17424    ) {
17425        if !self.diagnostics_enabled() {
17426            return;
17427        }
17428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17429        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17430    }
17431
17432    pub fn go_to_diagnostic_impl(
17433        &mut self,
17434        direction: Direction,
17435        severity: GoToDiagnosticSeverityFilter,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) {
17439        let buffer = self.buffer.read(cx).snapshot(cx);
17440        let selection = self
17441            .selections
17442            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17443
17444        let mut active_group_id = None;
17445        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17446            && active_group.active_range.start.to_offset(&buffer) == selection.start
17447        {
17448            active_group_id = Some(active_group.group_id);
17449        }
17450
17451        fn filtered<'a>(
17452            severity: GoToDiagnosticSeverityFilter,
17453            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17454        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17455            diagnostics
17456                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17457                .filter(|entry| entry.range.start != entry.range.end)
17458                .filter(|entry| !entry.diagnostic.is_unnecessary)
17459        }
17460
17461        let before = filtered(
17462            severity,
17463            buffer
17464                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17465                .filter(|entry| entry.range.start <= selection.start),
17466        );
17467        let after = filtered(
17468            severity,
17469            buffer
17470                .diagnostics_in_range(selection.start..buffer.len())
17471                .filter(|entry| entry.range.start >= selection.start),
17472        );
17473
17474        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17475        if direction == Direction::Prev {
17476            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17477            {
17478                for diagnostic in prev_diagnostics.into_iter().rev() {
17479                    if diagnostic.range.start != selection.start
17480                        || active_group_id
17481                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17482                    {
17483                        found = Some(diagnostic);
17484                        break 'outer;
17485                    }
17486                }
17487            }
17488        } else {
17489            for diagnostic in after.chain(before) {
17490                if diagnostic.range.start != selection.start
17491                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17492                {
17493                    found = Some(diagnostic);
17494                    break;
17495                }
17496            }
17497        }
17498        let Some(next_diagnostic) = found else {
17499            return;
17500        };
17501
17502        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17503        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17504            return;
17505        };
17506        let snapshot = self.snapshot(window, cx);
17507        if snapshot.intersects_fold(next_diagnostic.range.start) {
17508            self.unfold_ranges(
17509                std::slice::from_ref(&next_diagnostic.range),
17510                true,
17511                false,
17512                cx,
17513            );
17514        }
17515        self.change_selections(Default::default(), window, cx, |s| {
17516            s.select_ranges(vec![
17517                next_diagnostic.range.start..next_diagnostic.range.start,
17518            ])
17519        });
17520        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17521        self.refresh_edit_prediction(false, true, window, cx);
17522    }
17523
17524    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17526        let snapshot = self.snapshot(window, cx);
17527        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17528        self.go_to_hunk_before_or_after_position(
17529            &snapshot,
17530            selection.head(),
17531            Direction::Next,
17532            window,
17533            cx,
17534        );
17535    }
17536
17537    pub fn go_to_hunk_before_or_after_position(
17538        &mut self,
17539        snapshot: &EditorSnapshot,
17540        position: Point,
17541        direction: Direction,
17542        window: &mut Window,
17543        cx: &mut Context<Editor>,
17544    ) {
17545        let row = if direction == Direction::Next {
17546            self.hunk_after_position(snapshot, position)
17547                .map(|hunk| hunk.row_range.start)
17548        } else {
17549            self.hunk_before_position(snapshot, position)
17550        };
17551
17552        if let Some(row) = row {
17553            let destination = Point::new(row.0, 0);
17554            let autoscroll = Autoscroll::center();
17555
17556            self.unfold_ranges(&[destination..destination], false, false, cx);
17557            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17558                s.select_ranges([destination..destination]);
17559            });
17560        }
17561    }
17562
17563    fn hunk_after_position(
17564        &mut self,
17565        snapshot: &EditorSnapshot,
17566        position: Point,
17567    ) -> Option<MultiBufferDiffHunk> {
17568        snapshot
17569            .buffer_snapshot()
17570            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17571            .find(|hunk| hunk.row_range.start.0 > position.row)
17572            .or_else(|| {
17573                snapshot
17574                    .buffer_snapshot()
17575                    .diff_hunks_in_range(Point::zero()..position)
17576                    .find(|hunk| hunk.row_range.end.0 < position.row)
17577            })
17578    }
17579
17580    fn go_to_prev_hunk(
17581        &mut self,
17582        _: &GoToPreviousHunk,
17583        window: &mut Window,
17584        cx: &mut Context<Self>,
17585    ) {
17586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17587        let snapshot = self.snapshot(window, cx);
17588        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17589        self.go_to_hunk_before_or_after_position(
17590            &snapshot,
17591            selection.head(),
17592            Direction::Prev,
17593            window,
17594            cx,
17595        );
17596    }
17597
17598    fn hunk_before_position(
17599        &mut self,
17600        snapshot: &EditorSnapshot,
17601        position: Point,
17602    ) -> Option<MultiBufferRow> {
17603        snapshot
17604            .buffer_snapshot()
17605            .diff_hunk_before(position)
17606            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17607    }
17608
17609    fn go_to_next_change(
17610        &mut self,
17611        _: &GoToNextChange,
17612        window: &mut Window,
17613        cx: &mut Context<Self>,
17614    ) {
17615        if let Some(selections) = self
17616            .change_list
17617            .next_change(1, Direction::Next)
17618            .map(|s| s.to_vec())
17619        {
17620            self.change_selections(Default::default(), window, cx, |s| {
17621                let map = s.display_snapshot();
17622                s.select_display_ranges(selections.iter().map(|a| {
17623                    let point = a.to_display_point(&map);
17624                    point..point
17625                }))
17626            })
17627        }
17628    }
17629
17630    fn go_to_previous_change(
17631        &mut self,
17632        _: &GoToPreviousChange,
17633        window: &mut Window,
17634        cx: &mut Context<Self>,
17635    ) {
17636        if let Some(selections) = self
17637            .change_list
17638            .next_change(1, Direction::Prev)
17639            .map(|s| s.to_vec())
17640        {
17641            self.change_selections(Default::default(), window, cx, |s| {
17642                let map = s.display_snapshot();
17643                s.select_display_ranges(selections.iter().map(|a| {
17644                    let point = a.to_display_point(&map);
17645                    point..point
17646                }))
17647            })
17648        }
17649    }
17650
17651    pub fn go_to_next_document_highlight(
17652        &mut self,
17653        _: &GoToNextDocumentHighlight,
17654        window: &mut Window,
17655        cx: &mut Context<Self>,
17656    ) {
17657        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17658    }
17659
17660    pub fn go_to_prev_document_highlight(
17661        &mut self,
17662        _: &GoToPreviousDocumentHighlight,
17663        window: &mut Window,
17664        cx: &mut Context<Self>,
17665    ) {
17666        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17667    }
17668
17669    pub fn go_to_document_highlight_before_or_after_position(
17670        &mut self,
17671        direction: Direction,
17672        window: &mut Window,
17673        cx: &mut Context<Editor>,
17674    ) {
17675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17676        let snapshot = self.snapshot(window, cx);
17677        let buffer = &snapshot.buffer_snapshot();
17678        let position = self
17679            .selections
17680            .newest::<Point>(&snapshot.display_snapshot)
17681            .head();
17682        let anchor_position = buffer.anchor_after(position);
17683
17684        // Get all document highlights (both read and write)
17685        let mut all_highlights = Vec::new();
17686
17687        if let Some((_, read_highlights)) = self
17688            .background_highlights
17689            .get(&HighlightKey::DocumentHighlightRead)
17690        {
17691            all_highlights.extend(read_highlights.iter());
17692        }
17693
17694        if let Some((_, write_highlights)) = self
17695            .background_highlights
17696            .get(&HighlightKey::DocumentHighlightWrite)
17697        {
17698            all_highlights.extend(write_highlights.iter());
17699        }
17700
17701        if all_highlights.is_empty() {
17702            return;
17703        }
17704
17705        // Sort highlights by position
17706        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17707
17708        let target_highlight = match direction {
17709            Direction::Next => {
17710                // Find the first highlight after the current position
17711                all_highlights
17712                    .iter()
17713                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17714            }
17715            Direction::Prev => {
17716                // Find the last highlight before the current position
17717                all_highlights
17718                    .iter()
17719                    .rev()
17720                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17721            }
17722        };
17723
17724        if let Some(highlight) = target_highlight {
17725            let destination = highlight.start.to_point(buffer);
17726            let autoscroll = Autoscroll::center();
17727
17728            self.unfold_ranges(&[destination..destination], false, false, cx);
17729            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17730                s.select_ranges([destination..destination]);
17731            });
17732        }
17733    }
17734
17735    fn go_to_line<T: 'static>(
17736        &mut self,
17737        position: Anchor,
17738        highlight_color: Option<Hsla>,
17739        window: &mut Window,
17740        cx: &mut Context<Self>,
17741    ) {
17742        let snapshot = self.snapshot(window, cx).display_snapshot;
17743        let position = position.to_point(&snapshot.buffer_snapshot());
17744        let start = snapshot
17745            .buffer_snapshot()
17746            .clip_point(Point::new(position.row, 0), Bias::Left);
17747        let end = start + Point::new(1, 0);
17748        let start = snapshot.buffer_snapshot().anchor_before(start);
17749        let end = snapshot.buffer_snapshot().anchor_before(end);
17750
17751        self.highlight_rows::<T>(
17752            start..end,
17753            highlight_color
17754                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17755            Default::default(),
17756            cx,
17757        );
17758
17759        if self.buffer.read(cx).is_singleton() {
17760            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17761        }
17762    }
17763
17764    pub fn go_to_definition(
17765        &mut self,
17766        _: &GoToDefinition,
17767        window: &mut Window,
17768        cx: &mut Context<Self>,
17769    ) -> Task<Result<Navigated>> {
17770        let definition =
17771            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17772        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17773        cx.spawn_in(window, async move |editor, cx| {
17774            if definition.await? == Navigated::Yes {
17775                return Ok(Navigated::Yes);
17776            }
17777            match fallback_strategy {
17778                GoToDefinitionFallback::None => Ok(Navigated::No),
17779                GoToDefinitionFallback::FindAllReferences => {
17780                    match editor.update_in(cx, |editor, window, cx| {
17781                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17782                    })? {
17783                        Some(references) => references.await,
17784                        None => Ok(Navigated::No),
17785                    }
17786                }
17787            }
17788        })
17789    }
17790
17791    pub fn go_to_declaration(
17792        &mut self,
17793        _: &GoToDeclaration,
17794        window: &mut Window,
17795        cx: &mut Context<Self>,
17796    ) -> Task<Result<Navigated>> {
17797        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17798    }
17799
17800    pub fn go_to_declaration_split(
17801        &mut self,
17802        _: &GoToDeclaration,
17803        window: &mut Window,
17804        cx: &mut Context<Self>,
17805    ) -> Task<Result<Navigated>> {
17806        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17807    }
17808
17809    pub fn go_to_implementation(
17810        &mut self,
17811        _: &GoToImplementation,
17812        window: &mut Window,
17813        cx: &mut Context<Self>,
17814    ) -> Task<Result<Navigated>> {
17815        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17816    }
17817
17818    pub fn go_to_implementation_split(
17819        &mut self,
17820        _: &GoToImplementationSplit,
17821        window: &mut Window,
17822        cx: &mut Context<Self>,
17823    ) -> Task<Result<Navigated>> {
17824        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17825    }
17826
17827    pub fn go_to_type_definition(
17828        &mut self,
17829        _: &GoToTypeDefinition,
17830        window: &mut Window,
17831        cx: &mut Context<Self>,
17832    ) -> Task<Result<Navigated>> {
17833        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17834    }
17835
17836    pub fn go_to_definition_split(
17837        &mut self,
17838        _: &GoToDefinitionSplit,
17839        window: &mut Window,
17840        cx: &mut Context<Self>,
17841    ) -> Task<Result<Navigated>> {
17842        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17843    }
17844
17845    pub fn go_to_type_definition_split(
17846        &mut self,
17847        _: &GoToTypeDefinitionSplit,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) -> Task<Result<Navigated>> {
17851        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17852    }
17853
17854    fn go_to_definition_of_kind(
17855        &mut self,
17856        kind: GotoDefinitionKind,
17857        split: bool,
17858        window: &mut Window,
17859        cx: &mut Context<Self>,
17860    ) -> Task<Result<Navigated>> {
17861        let Some(provider) = self.semantics_provider.clone() else {
17862            return Task::ready(Ok(Navigated::No));
17863        };
17864        let head = self
17865            .selections
17866            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17867            .head();
17868        let buffer = self.buffer.read(cx);
17869        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17870            return Task::ready(Ok(Navigated::No));
17871        };
17872        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17873            return Task::ready(Ok(Navigated::No));
17874        };
17875
17876        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
17877
17878        cx.spawn_in(window, async move |editor, cx| {
17879            let Some(definitions) = definitions.await? else {
17880                return Ok(Navigated::No);
17881            };
17882            let navigated = editor
17883                .update_in(cx, |editor, window, cx| {
17884                    editor.navigate_to_hover_links(
17885                        Some(kind),
17886                        definitions
17887                            .into_iter()
17888                            .filter(|location| {
17889                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17890                            })
17891                            .map(HoverLink::Text)
17892                            .collect::<Vec<_>>(),
17893                        nav_entry,
17894                        split,
17895                        window,
17896                        cx,
17897                    )
17898                })?
17899                .await?;
17900            anyhow::Ok(navigated)
17901        })
17902    }
17903
17904    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17905        let selection = self.selections.newest_anchor();
17906        let head = selection.head();
17907        let tail = selection.tail();
17908
17909        let Some((buffer, start_position)) =
17910            self.buffer.read(cx).text_anchor_for_position(head, cx)
17911        else {
17912            return;
17913        };
17914
17915        let end_position = if head != tail {
17916            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17917                return;
17918            };
17919            Some(pos)
17920        } else {
17921            None
17922        };
17923
17924        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17925            let url = if let Some(end_pos) = end_position {
17926                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17927            } else {
17928                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17929            };
17930
17931            if let Some(url) = url {
17932                cx.update(|window, cx| {
17933                    if parse_zed_link(&url, cx).is_some() {
17934                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17935                    } else {
17936                        cx.open_url(&url);
17937                    }
17938                })?;
17939            }
17940
17941            anyhow::Ok(())
17942        });
17943
17944        url_finder.detach();
17945    }
17946
17947    pub fn open_selected_filename(
17948        &mut self,
17949        _: &OpenSelectedFilename,
17950        window: &mut Window,
17951        cx: &mut Context<Self>,
17952    ) {
17953        let Some(workspace) = self.workspace() else {
17954            return;
17955        };
17956
17957        let position = self.selections.newest_anchor().head();
17958
17959        let Some((buffer, buffer_position)) =
17960            self.buffer.read(cx).text_anchor_for_position(position, cx)
17961        else {
17962            return;
17963        };
17964
17965        let project = self.project.clone();
17966
17967        cx.spawn_in(window, async move |_, cx| {
17968            let result = find_file(&buffer, project, buffer_position, cx).await;
17969
17970            if let Some((_, path)) = result {
17971                workspace
17972                    .update_in(cx, |workspace, window, cx| {
17973                        workspace.open_resolved_path(path, window, cx)
17974                    })?
17975                    .await?;
17976            }
17977            anyhow::Ok(())
17978        })
17979        .detach();
17980    }
17981
17982    pub(crate) fn navigate_to_hover_links(
17983        &mut self,
17984        kind: Option<GotoDefinitionKind>,
17985        definitions: Vec<HoverLink>,
17986        origin: Option<NavigationEntry>,
17987        split: bool,
17988        window: &mut Window,
17989        cx: &mut Context<Editor>,
17990    ) -> Task<Result<Navigated>> {
17991        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17992        let mut first_url_or_file = None;
17993        let definitions: Vec<_> = definitions
17994            .into_iter()
17995            .filter_map(|def| match def {
17996                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17997                HoverLink::InlayHint(lsp_location, server_id) => {
17998                    let computation =
17999                        self.compute_target_location(lsp_location, server_id, window, cx);
18000                    Some(cx.background_spawn(computation))
18001                }
18002                HoverLink::Url(url) => {
18003                    first_url_or_file = Some(Either::Left(url));
18004                    None
18005                }
18006                HoverLink::File(path) => {
18007                    first_url_or_file = Some(Either::Right(path));
18008                    None
18009                }
18010            })
18011            .collect();
18012
18013        let workspace = self.workspace();
18014
18015        cx.spawn_in(window, async move |editor, cx| {
18016            let locations: Vec<Location> = future::join_all(definitions)
18017                .await
18018                .into_iter()
18019                .filter_map(|location| location.transpose())
18020                .collect::<Result<_>>()
18021                .context("location tasks")?;
18022            let mut locations = cx.update(|_, cx| {
18023                locations
18024                    .into_iter()
18025                    .map(|location| {
18026                        let buffer = location.buffer.read(cx);
18027                        (location.buffer, location.range.to_point(buffer))
18028                    })
18029                    .into_group_map()
18030            })?;
18031            let mut num_locations = 0;
18032            for ranges in locations.values_mut() {
18033                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18034                ranges.dedup();
18035                num_locations += ranges.len();
18036            }
18037
18038            if num_locations > 1 {
18039                let tab_kind = match kind {
18040                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18041                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18042                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18043                    Some(GotoDefinitionKind::Type) => "Types",
18044                };
18045                let title = editor
18046                    .update_in(cx, |_, _, cx| {
18047                        let target = locations
18048                            .iter()
18049                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18050                            .map(|(buffer, location)| {
18051                                buffer
18052                                    .read(cx)
18053                                    .text_for_range(location.clone())
18054                                    .collect::<String>()
18055                            })
18056                            .filter(|text| !text.contains('\n'))
18057                            .unique()
18058                            .take(3)
18059                            .join(", ");
18060                        if target.is_empty() {
18061                            tab_kind.to_owned()
18062                        } else {
18063                            format!("{tab_kind} for {target}")
18064                        }
18065                    })
18066                    .context("buffer title")?;
18067
18068                let Some(workspace) = workspace else {
18069                    return Ok(Navigated::No);
18070                };
18071
18072                let opened = workspace
18073                    .update_in(cx, |workspace, window, cx| {
18074                        let allow_preview = PreviewTabsSettings::get_global(cx)
18075                            .enable_preview_multibuffer_from_code_navigation;
18076                        if let Some((target_editor, target_pane)) =
18077                            Self::open_locations_in_multibuffer(
18078                                workspace,
18079                                locations,
18080                                title,
18081                                split,
18082                                allow_preview,
18083                                MultibufferSelectionMode::First,
18084                                window,
18085                                cx,
18086                            )
18087                        {
18088                            // We create our own nav history instead of using
18089                            // `target_editor.nav_history` because `nav_history`
18090                            // seems to be populated asynchronously when an item
18091                            // is added to a pane
18092                            let mut nav_history = target_pane
18093                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18094                            target_editor.update(cx, |editor, cx| {
18095                                let nav_data = editor
18096                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18097                                let target =
18098                                    Some(nav_history.navigation_entry(Some(
18099                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18100                                    )));
18101                                nav_history.push_tag(origin, target);
18102                            })
18103                        }
18104                    })
18105                    .is_ok();
18106
18107                anyhow::Ok(Navigated::from_bool(opened))
18108            } else if num_locations == 0 {
18109                // If there is one url or file, open it directly
18110                match first_url_or_file {
18111                    Some(Either::Left(url)) => {
18112                        cx.update(|window, cx| {
18113                            if parse_zed_link(&url, cx).is_some() {
18114                                window
18115                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18116                            } else {
18117                                cx.open_url(&url);
18118                            }
18119                        })?;
18120                        Ok(Navigated::Yes)
18121                    }
18122                    Some(Either::Right(path)) => {
18123                        // TODO(andrew): respect preview tab settings
18124                        //               `enable_keep_preview_on_code_navigation` and
18125                        //               `enable_preview_file_from_code_navigation`
18126                        let Some(workspace) = workspace else {
18127                            return Ok(Navigated::No);
18128                        };
18129                        workspace
18130                            .update_in(cx, |workspace, window, cx| {
18131                                workspace.open_resolved_path(path, window, cx)
18132                            })?
18133                            .await?;
18134                        Ok(Navigated::Yes)
18135                    }
18136                    None => Ok(Navigated::No),
18137                }
18138            } else {
18139                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18140                let target_range = target_ranges.first().unwrap().clone();
18141
18142                editor.update_in(cx, |editor, window, cx| {
18143                    let range = editor.range_for_match(&target_range);
18144                    let range = collapse_multiline_range(range);
18145
18146                    if !split
18147                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18148                    {
18149                        editor.go_to_singleton_buffer_range(range, window, cx);
18150
18151                        let target =
18152                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18153                        if let Some(mut nav_history) = editor.nav_history.clone() {
18154                            nav_history.push_tag(origin, target);
18155                        }
18156                    } else {
18157                        let Some(workspace) = workspace else {
18158                            return Navigated::No;
18159                        };
18160                        let pane = workspace.read(cx).active_pane().clone();
18161                        window.defer(cx, move |window, cx| {
18162                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18163                                workspace.update(cx, |workspace, cx| {
18164                                    let pane = if split {
18165                                        workspace.adjacent_pane(window, cx)
18166                                    } else {
18167                                        workspace.active_pane().clone()
18168                                    };
18169
18170                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18171                                    let keep_old_preview = preview_tabs_settings
18172                                        .enable_keep_preview_on_code_navigation;
18173                                    let allow_new_preview = preview_tabs_settings
18174                                        .enable_preview_file_from_code_navigation;
18175
18176                                    let editor = workspace.open_project_item(
18177                                        pane.clone(),
18178                                        target_buffer.clone(),
18179                                        true,
18180                                        true,
18181                                        keep_old_preview,
18182                                        allow_new_preview,
18183                                        window,
18184                                        cx,
18185                                    );
18186                                    (editor, pane)
18187                                });
18188                            // We create our own nav history instead of using
18189                            // `target_editor.nav_history` because `nav_history`
18190                            // seems to be populated asynchronously when an item
18191                            // is added to a pane
18192                            let mut nav_history = target_pane
18193                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18194                            target_editor.update(cx, |target_editor, cx| {
18195                                // When selecting a definition in a different buffer, disable the nav history
18196                                // to avoid creating a history entry at the previous cursor location.
18197                                pane.update(cx, |pane, _| pane.disable_history());
18198                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18199
18200                                let nav_data = target_editor.navigation_data(
18201                                    target_editor.selections.newest_anchor().head(),
18202                                    cx,
18203                                );
18204                                let target =
18205                                    Some(nav_history.navigation_entry(Some(
18206                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18207                                    )));
18208                                nav_history.push_tag(origin, target);
18209                                pane.update(cx, |pane, _| pane.enable_history());
18210                            });
18211                        });
18212                    }
18213                    Navigated::Yes
18214                })
18215            }
18216        })
18217    }
18218
18219    fn compute_target_location(
18220        &self,
18221        lsp_location: lsp::Location,
18222        server_id: LanguageServerId,
18223        window: &mut Window,
18224        cx: &mut Context<Self>,
18225    ) -> Task<anyhow::Result<Option<Location>>> {
18226        let Some(project) = self.project.clone() else {
18227            return Task::ready(Ok(None));
18228        };
18229
18230        cx.spawn_in(window, async move |editor, cx| {
18231            let location_task = editor.update(cx, |_, cx| {
18232                project.update(cx, |project, cx| {
18233                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18234                })
18235            })?;
18236            let location = Some({
18237                let target_buffer_handle = location_task.await.context("open local buffer")?;
18238                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18239                    let target_start = target_buffer
18240                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18241                    let target_end = target_buffer
18242                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18243                    target_buffer.anchor_after(target_start)
18244                        ..target_buffer.anchor_before(target_end)
18245                });
18246                Location {
18247                    buffer: target_buffer_handle,
18248                    range,
18249                }
18250            });
18251            Ok(location)
18252        })
18253    }
18254
18255    fn go_to_next_reference(
18256        &mut self,
18257        _: &GoToNextReference,
18258        window: &mut Window,
18259        cx: &mut Context<Self>,
18260    ) {
18261        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18262        if let Some(task) = task {
18263            task.detach();
18264        };
18265    }
18266
18267    fn go_to_prev_reference(
18268        &mut self,
18269        _: &GoToPreviousReference,
18270        window: &mut Window,
18271        cx: &mut Context<Self>,
18272    ) {
18273        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18274        if let Some(task) = task {
18275            task.detach();
18276        };
18277    }
18278
18279    pub fn go_to_reference_before_or_after_position(
18280        &mut self,
18281        direction: Direction,
18282        count: usize,
18283        window: &mut Window,
18284        cx: &mut Context<Self>,
18285    ) -> Option<Task<Result<()>>> {
18286        let selection = self.selections.newest_anchor();
18287        let head = selection.head();
18288
18289        let multi_buffer = self.buffer.read(cx);
18290
18291        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18292        let workspace = self.workspace()?;
18293        let project = workspace.read(cx).project().clone();
18294        let references =
18295            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18296        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18297            let Some(locations) = references.await? else {
18298                return Ok(());
18299            };
18300
18301            if locations.is_empty() {
18302                // totally normal - the cursor may be on something which is not
18303                // a symbol (e.g. a keyword)
18304                log::info!("no references found under cursor");
18305                return Ok(());
18306            }
18307
18308            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18309
18310            let (locations, current_location_index) =
18311                multi_buffer.update(cx, |multi_buffer, cx| {
18312                    let mut locations = locations
18313                        .into_iter()
18314                        .filter_map(|loc| {
18315                            let start = multi_buffer.buffer_anchor_to_anchor(
18316                                &loc.buffer,
18317                                loc.range.start,
18318                                cx,
18319                            )?;
18320                            let end = multi_buffer.buffer_anchor_to_anchor(
18321                                &loc.buffer,
18322                                loc.range.end,
18323                                cx,
18324                            )?;
18325                            Some(start..end)
18326                        })
18327                        .collect::<Vec<_>>();
18328
18329                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18330                    // There is an O(n) implementation, but given this list will be
18331                    // small (usually <100 items), the extra O(log(n)) factor isn't
18332                    // worth the (surprisingly large amount of) extra complexity.
18333                    locations
18334                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18335
18336                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18337
18338                    let current_location_index = locations.iter().position(|loc| {
18339                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18340                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18341                    });
18342
18343                    (locations, current_location_index)
18344                });
18345
18346            let Some(current_location_index) = current_location_index else {
18347                // This indicates something has gone wrong, because we already
18348                // handle the "no references" case above
18349                log::error!(
18350                    "failed to find current reference under cursor. Total references: {}",
18351                    locations.len()
18352                );
18353                return Ok(());
18354            };
18355
18356            let destination_location_index = match direction {
18357                Direction::Next => (current_location_index + count) % locations.len(),
18358                Direction::Prev => {
18359                    (current_location_index + locations.len() - count % locations.len())
18360                        % locations.len()
18361                }
18362            };
18363
18364            // TODO(cameron): is this needed?
18365            // the thinking is to avoid "jumping to the current location" (avoid
18366            // polluting "jumplist" in vim terms)
18367            if current_location_index == destination_location_index {
18368                return Ok(());
18369            }
18370
18371            let Range { start, end } = locations[destination_location_index];
18372
18373            editor.update_in(cx, |editor, window, cx| {
18374                let effects = SelectionEffects::default();
18375
18376                editor.unfold_ranges(&[start..end], false, false, cx);
18377                editor.change_selections(effects, window, cx, |s| {
18378                    s.select_ranges([start..start]);
18379                });
18380            })?;
18381
18382            Ok(())
18383        }))
18384    }
18385
18386    pub fn find_all_references(
18387        &mut self,
18388        action: &FindAllReferences,
18389        window: &mut Window,
18390        cx: &mut Context<Self>,
18391    ) -> Option<Task<Result<Navigated>>> {
18392        let always_open_multibuffer = action.always_open_multibuffer;
18393        let selection = self.selections.newest_anchor();
18394        let multi_buffer = self.buffer.read(cx);
18395        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18396        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18397        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18398        let head = selection_offset.head();
18399
18400        let head_anchor = multi_buffer_snapshot.anchor_at(
18401            head,
18402            if head < selection_offset.tail() {
18403                Bias::Right
18404            } else {
18405                Bias::Left
18406            },
18407        );
18408
18409        match self
18410            .find_all_references_task_sources
18411            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18412        {
18413            Ok(_) => {
18414                log::info!(
18415                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18416                );
18417                return None;
18418            }
18419            Err(i) => {
18420                self.find_all_references_task_sources.insert(i, head_anchor);
18421            }
18422        }
18423
18424        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18425        let workspace = self.workspace()?;
18426        let project = workspace.read(cx).project().clone();
18427        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18428        Some(cx.spawn_in(window, async move |editor, cx| {
18429            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18430                if let Ok(i) = editor
18431                    .find_all_references_task_sources
18432                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18433                {
18434                    editor.find_all_references_task_sources.remove(i);
18435                }
18436            });
18437
18438            let Some(locations) = references.await? else {
18439                return anyhow::Ok(Navigated::No);
18440            };
18441            let mut locations = cx.update(|_, cx| {
18442                locations
18443                    .into_iter()
18444                    .map(|location| {
18445                        let buffer = location.buffer.read(cx);
18446                        (location.buffer, location.range.to_point(buffer))
18447                    })
18448                    // if special-casing the single-match case, remove ranges
18449                    // that intersect current selection
18450                    .filter(|(location_buffer, location)| {
18451                        if always_open_multibuffer || &buffer != location_buffer {
18452                            return true;
18453                        }
18454
18455                        !location.contains_inclusive(&selection_point.range())
18456                    })
18457                    .into_group_map()
18458            })?;
18459            if locations.is_empty() {
18460                return anyhow::Ok(Navigated::No);
18461            }
18462            for ranges in locations.values_mut() {
18463                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18464                ranges.dedup();
18465            }
18466            let mut num_locations = 0;
18467            for ranges in locations.values_mut() {
18468                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18469                ranges.dedup();
18470                num_locations += ranges.len();
18471            }
18472
18473            if num_locations == 1 && !always_open_multibuffer {
18474                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18475                let target_range = target_ranges.first().unwrap().clone();
18476
18477                return editor.update_in(cx, |editor, window, cx| {
18478                    let range = target_range.to_point(target_buffer.read(cx));
18479                    let range = editor.range_for_match(&range);
18480                    let range = range.start..range.start;
18481
18482                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18483                        editor.go_to_singleton_buffer_range(range, window, cx);
18484                    } else {
18485                        let pane = workspace.read(cx).active_pane().clone();
18486                        window.defer(cx, move |window, cx| {
18487                            let target_editor: Entity<Self> =
18488                                workspace.update(cx, |workspace, cx| {
18489                                    let pane = workspace.active_pane().clone();
18490
18491                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18492                                    let keep_old_preview = preview_tabs_settings
18493                                        .enable_keep_preview_on_code_navigation;
18494                                    let allow_new_preview = preview_tabs_settings
18495                                        .enable_preview_file_from_code_navigation;
18496
18497                                    workspace.open_project_item(
18498                                        pane,
18499                                        target_buffer.clone(),
18500                                        true,
18501                                        true,
18502                                        keep_old_preview,
18503                                        allow_new_preview,
18504                                        window,
18505                                        cx,
18506                                    )
18507                                });
18508                            target_editor.update(cx, |target_editor, cx| {
18509                                // When selecting a definition in a different buffer, disable the nav history
18510                                // to avoid creating a history entry at the previous cursor location.
18511                                pane.update(cx, |pane, _| pane.disable_history());
18512                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18513                                pane.update(cx, |pane, _| pane.enable_history());
18514                            });
18515                        });
18516                    }
18517                    Navigated::No
18518                });
18519            }
18520
18521            workspace.update_in(cx, |workspace, window, cx| {
18522                let target = locations
18523                    .iter()
18524                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18525                    .map(|(buffer, location)| {
18526                        buffer
18527                            .read(cx)
18528                            .text_for_range(location.clone())
18529                            .collect::<String>()
18530                    })
18531                    .filter(|text| !text.contains('\n'))
18532                    .unique()
18533                    .take(3)
18534                    .join(", ");
18535                let title = if target.is_empty() {
18536                    "References".to_owned()
18537                } else {
18538                    format!("References to {target}")
18539                };
18540                let allow_preview = PreviewTabsSettings::get_global(cx)
18541                    .enable_preview_multibuffer_from_code_navigation;
18542                Self::open_locations_in_multibuffer(
18543                    workspace,
18544                    locations,
18545                    title,
18546                    false,
18547                    allow_preview,
18548                    MultibufferSelectionMode::First,
18549                    window,
18550                    cx,
18551                );
18552                Navigated::Yes
18553            })
18554        }))
18555    }
18556
18557    /// Opens a multibuffer with the given project locations in it.
18558    pub fn open_locations_in_multibuffer(
18559        workspace: &mut Workspace,
18560        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18561        title: String,
18562        split: bool,
18563        allow_preview: bool,
18564        multibuffer_selection_mode: MultibufferSelectionMode,
18565        window: &mut Window,
18566        cx: &mut Context<Workspace>,
18567    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18568        if locations.is_empty() {
18569            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18570            return None;
18571        }
18572
18573        let capability = workspace.project().read(cx).capability();
18574        let mut ranges = <Vec<Range<Anchor>>>::new();
18575
18576        // a key to find existing multibuffer editors with the same set of locations
18577        // to prevent us from opening more and more multibuffer tabs for searches and the like
18578        let mut key = (title.clone(), vec![]);
18579        let excerpt_buffer = cx.new(|cx| {
18580            let key = &mut key.1;
18581            let mut multibuffer = MultiBuffer::new(capability);
18582            for (buffer, mut ranges_for_buffer) in locations {
18583                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18584                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18585                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18586                    PathKey::for_buffer(&buffer, cx),
18587                    buffer.clone(),
18588                    ranges_for_buffer,
18589                    multibuffer_context_lines(cx),
18590                    cx,
18591                );
18592                ranges.extend(new_ranges)
18593            }
18594
18595            multibuffer.with_title(title)
18596        });
18597        let existing = workspace.active_pane().update(cx, |pane, cx| {
18598            pane.items()
18599                .filter_map(|item| item.downcast::<Editor>())
18600                .find(|editor| {
18601                    editor
18602                        .read(cx)
18603                        .lookup_key
18604                        .as_ref()
18605                        .and_then(|it| {
18606                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18607                        })
18608                        .is_some_and(|it| *it == key)
18609                })
18610        });
18611        let was_existing = existing.is_some();
18612        let editor = existing.unwrap_or_else(|| {
18613            cx.new(|cx| {
18614                let mut editor = Editor::for_multibuffer(
18615                    excerpt_buffer,
18616                    Some(workspace.project().clone()),
18617                    window,
18618                    cx,
18619                );
18620                editor.lookup_key = Some(Box::new(key));
18621                editor
18622            })
18623        });
18624        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18625            MultibufferSelectionMode::First => {
18626                if let Some(first_range) = ranges.first() {
18627                    editor.change_selections(
18628                        SelectionEffects::no_scroll(),
18629                        window,
18630                        cx,
18631                        |selections| {
18632                            selections.clear_disjoint();
18633                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18634                        },
18635                    );
18636                }
18637                editor.highlight_background(
18638                    HighlightKey::Editor,
18639                    &ranges,
18640                    |_, theme| theme.colors().editor_highlighted_line_background,
18641                    cx,
18642                );
18643            }
18644            MultibufferSelectionMode::All => {
18645                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18646                    selections.clear_disjoint();
18647                    selections.select_anchor_ranges(ranges);
18648                });
18649            }
18650        });
18651
18652        let item = Box::new(editor.clone());
18653
18654        let pane = if split {
18655            workspace.adjacent_pane(window, cx)
18656        } else {
18657            workspace.active_pane().clone()
18658        };
18659        let activate_pane = split;
18660
18661        let mut destination_index = None;
18662        pane.update(cx, |pane, cx| {
18663            if allow_preview && !was_existing {
18664                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18665            }
18666            if was_existing && !allow_preview {
18667                pane.unpreview_item_if_preview(item.item_id());
18668            }
18669            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18670        });
18671
18672        Some((editor, pane))
18673    }
18674
18675    pub fn rename(
18676        &mut self,
18677        _: &Rename,
18678        window: &mut Window,
18679        cx: &mut Context<Self>,
18680    ) -> Option<Task<Result<()>>> {
18681        use language::ToOffset as _;
18682
18683        let provider = self.semantics_provider.clone()?;
18684        let selection = self.selections.newest_anchor().clone();
18685        let (cursor_buffer, cursor_buffer_position) = self
18686            .buffer
18687            .read(cx)
18688            .text_anchor_for_position(selection.head(), cx)?;
18689        let (tail_buffer, cursor_buffer_position_end) = self
18690            .buffer
18691            .read(cx)
18692            .text_anchor_for_position(selection.tail(), cx)?;
18693        if tail_buffer != cursor_buffer {
18694            return None;
18695        }
18696
18697        let snapshot = cursor_buffer.read(cx).snapshot();
18698        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18699        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18700        let prepare_rename = provider
18701            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18702            .unwrap_or_else(|| Task::ready(Ok(None)));
18703        drop(snapshot);
18704
18705        Some(cx.spawn_in(window, async move |this, cx| {
18706            let rename_range = if let Some(range) = prepare_rename.await? {
18707                Some(range)
18708            } else {
18709                this.update(cx, |this, cx| {
18710                    let buffer = this.buffer.read(cx).snapshot(cx);
18711                    let mut buffer_highlights = this
18712                        .document_highlights_for_position(selection.head(), &buffer)
18713                        .filter(|highlight| {
18714                            highlight.start.excerpt_id == selection.head().excerpt_id
18715                                && highlight.end.excerpt_id == selection.head().excerpt_id
18716                        });
18717                    buffer_highlights
18718                        .next()
18719                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18720                })?
18721            };
18722            if let Some(rename_range) = rename_range {
18723                this.update_in(cx, |this, window, cx| {
18724                    let snapshot = cursor_buffer.read(cx).snapshot();
18725                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18726                    let cursor_offset_in_rename_range =
18727                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18728                    let cursor_offset_in_rename_range_end =
18729                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18730
18731                    this.take_rename(false, window, cx);
18732                    let buffer = this.buffer.read(cx).read(cx);
18733                    let cursor_offset = selection.head().to_offset(&buffer);
18734                    let rename_start =
18735                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18736                    let rename_end = rename_start + rename_buffer_range.len();
18737                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18738                    let mut old_highlight_id = None;
18739                    let old_name: Arc<str> = buffer
18740                        .chunks(rename_start..rename_end, true)
18741                        .map(|chunk| {
18742                            if old_highlight_id.is_none() {
18743                                old_highlight_id = chunk.syntax_highlight_id;
18744                            }
18745                            chunk.text
18746                        })
18747                        .collect::<String>()
18748                        .into();
18749
18750                    drop(buffer);
18751
18752                    // Position the selection in the rename editor so that it matches the current selection.
18753                    this.show_local_selections = false;
18754                    let rename_editor = cx.new(|cx| {
18755                        let mut editor = Editor::single_line(window, cx);
18756                        editor.buffer.update(cx, |buffer, cx| {
18757                            buffer.edit(
18758                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18759                                None,
18760                                cx,
18761                            )
18762                        });
18763                        let cursor_offset_in_rename_range =
18764                            MultiBufferOffset(cursor_offset_in_rename_range);
18765                        let cursor_offset_in_rename_range_end =
18766                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18767                        let rename_selection_range = match cursor_offset_in_rename_range
18768                            .cmp(&cursor_offset_in_rename_range_end)
18769                        {
18770                            Ordering::Equal => {
18771                                editor.select_all(&SelectAll, window, cx);
18772                                return editor;
18773                            }
18774                            Ordering::Less => {
18775                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18776                            }
18777                            Ordering::Greater => {
18778                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18779                            }
18780                        };
18781                        if rename_selection_range.end.0 > old_name.len() {
18782                            editor.select_all(&SelectAll, window, cx);
18783                        } else {
18784                            editor.change_selections(Default::default(), window, cx, |s| {
18785                                s.select_ranges([rename_selection_range]);
18786                            });
18787                        }
18788                        editor
18789                    });
18790                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18791                        if e == &EditorEvent::Focused {
18792                            cx.emit(EditorEvent::FocusedIn)
18793                        }
18794                    })
18795                    .detach();
18796
18797                    let write_highlights =
18798                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
18799                    let read_highlights =
18800                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
18801                    let ranges = write_highlights
18802                        .iter()
18803                        .flat_map(|(_, ranges)| ranges.iter())
18804                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18805                        .cloned()
18806                        .collect();
18807
18808                    this.highlight_text(
18809                        HighlightKey::Rename,
18810                        ranges,
18811                        HighlightStyle {
18812                            fade_out: Some(0.6),
18813                            ..Default::default()
18814                        },
18815                        cx,
18816                    );
18817                    let rename_focus_handle = rename_editor.focus_handle(cx);
18818                    window.focus(&rename_focus_handle, cx);
18819                    let block_id = this.insert_blocks(
18820                        [BlockProperties {
18821                            style: BlockStyle::Flex,
18822                            placement: BlockPlacement::Below(range.start),
18823                            height: Some(1),
18824                            render: Arc::new({
18825                                let rename_editor = rename_editor.clone();
18826                                move |cx: &mut BlockContext| {
18827                                    let mut text_style = cx.editor_style.text.clone();
18828                                    if let Some(highlight_style) = old_highlight_id
18829                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18830                                    {
18831                                        text_style = text_style.highlight(highlight_style);
18832                                    }
18833                                    div()
18834                                        .block_mouse_except_scroll()
18835                                        .pl(cx.anchor_x)
18836                                        .child(EditorElement::new(
18837                                            &rename_editor,
18838                                            EditorStyle {
18839                                                background: cx.theme().system().transparent,
18840                                                local_player: cx.editor_style.local_player,
18841                                                text: text_style,
18842                                                scrollbar_width: cx.editor_style.scrollbar_width,
18843                                                syntax: cx.editor_style.syntax.clone(),
18844                                                status: cx.editor_style.status.clone(),
18845                                                inlay_hints_style: HighlightStyle {
18846                                                    font_weight: Some(FontWeight::BOLD),
18847                                                    ..make_inlay_hints_style(cx.app)
18848                                                },
18849                                                edit_prediction_styles: make_suggestion_styles(
18850                                                    cx.app,
18851                                                ),
18852                                                ..EditorStyle::default()
18853                                            },
18854                                        ))
18855                                        .into_any_element()
18856                                }
18857                            }),
18858                            priority: 0,
18859                        }],
18860                        Some(Autoscroll::fit()),
18861                        cx,
18862                    )[0];
18863                    this.pending_rename = Some(RenameState {
18864                        range,
18865                        old_name,
18866                        editor: rename_editor,
18867                        block_id,
18868                    });
18869                })?;
18870            }
18871
18872            Ok(())
18873        }))
18874    }
18875
18876    pub fn confirm_rename(
18877        &mut self,
18878        _: &ConfirmRename,
18879        window: &mut Window,
18880        cx: &mut Context<Self>,
18881    ) -> Option<Task<Result<()>>> {
18882        let rename = self.take_rename(false, window, cx)?;
18883        let workspace = self.workspace()?.downgrade();
18884        let (buffer, start) = self
18885            .buffer
18886            .read(cx)
18887            .text_anchor_for_position(rename.range.start, cx)?;
18888        let (end_buffer, _) = self
18889            .buffer
18890            .read(cx)
18891            .text_anchor_for_position(rename.range.end, cx)?;
18892        if buffer != end_buffer {
18893            return None;
18894        }
18895
18896        let old_name = rename.old_name;
18897        let new_name = rename.editor.read(cx).text(cx);
18898
18899        let rename = self.semantics_provider.as_ref()?.perform_rename(
18900            &buffer,
18901            start,
18902            new_name.clone(),
18903            cx,
18904        )?;
18905
18906        Some(cx.spawn_in(window, async move |editor, cx| {
18907            let project_transaction = rename.await?;
18908            Self::open_project_transaction(
18909                &editor,
18910                workspace,
18911                project_transaction,
18912                format!("Rename: {}{}", old_name, new_name),
18913                cx,
18914            )
18915            .await?;
18916
18917            editor.update(cx, |editor, cx| {
18918                editor.refresh_document_highlights(cx);
18919            })?;
18920            Ok(())
18921        }))
18922    }
18923
18924    fn take_rename(
18925        &mut self,
18926        moving_cursor: bool,
18927        window: &mut Window,
18928        cx: &mut Context<Self>,
18929    ) -> Option<RenameState> {
18930        let rename = self.pending_rename.take()?;
18931        if rename.editor.focus_handle(cx).is_focused(window) {
18932            window.focus(&self.focus_handle, cx);
18933        }
18934
18935        self.remove_blocks(
18936            [rename.block_id].into_iter().collect(),
18937            Some(Autoscroll::fit()),
18938            cx,
18939        );
18940        self.clear_highlights(HighlightKey::Rename, cx);
18941        self.show_local_selections = true;
18942
18943        if moving_cursor {
18944            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18945                editor
18946                    .selections
18947                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18948                    .head()
18949            });
18950
18951            // Update the selection to match the position of the selection inside
18952            // the rename editor.
18953            let snapshot = self.buffer.read(cx).read(cx);
18954            let rename_range = rename.range.to_offset(&snapshot);
18955            let cursor_in_editor = snapshot
18956                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18957                .min(rename_range.end);
18958            drop(snapshot);
18959
18960            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18961                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18962            });
18963        } else {
18964            self.refresh_document_highlights(cx);
18965        }
18966
18967        Some(rename)
18968    }
18969
18970    pub fn pending_rename(&self) -> Option<&RenameState> {
18971        self.pending_rename.as_ref()
18972    }
18973
18974    fn format(
18975        &mut self,
18976        _: &Format,
18977        window: &mut Window,
18978        cx: &mut Context<Self>,
18979    ) -> Option<Task<Result<()>>> {
18980        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18981
18982        let project = match &self.project {
18983            Some(project) => project.clone(),
18984            None => return None,
18985        };
18986
18987        Some(self.perform_format(
18988            project,
18989            FormatTrigger::Manual,
18990            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18991            window,
18992            cx,
18993        ))
18994    }
18995
18996    fn format_selections(
18997        &mut self,
18998        _: &FormatSelections,
18999        window: &mut Window,
19000        cx: &mut Context<Self>,
19001    ) -> Option<Task<Result<()>>> {
19002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19003
19004        let project = match &self.project {
19005            Some(project) => project.clone(),
19006            None => return None,
19007        };
19008
19009        let ranges = self
19010            .selections
19011            .all_adjusted(&self.display_snapshot(cx))
19012            .into_iter()
19013            .map(|selection| selection.range())
19014            .collect_vec();
19015
19016        Some(self.perform_format(
19017            project,
19018            FormatTrigger::Manual,
19019            FormatTarget::Ranges(ranges),
19020            window,
19021            cx,
19022        ))
19023    }
19024
19025    fn perform_format(
19026        &mut self,
19027        project: Entity<Project>,
19028        trigger: FormatTrigger,
19029        target: FormatTarget,
19030        window: &mut Window,
19031        cx: &mut Context<Self>,
19032    ) -> Task<Result<()>> {
19033        let buffer = self.buffer.clone();
19034        let (buffers, target) = match target {
19035            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19036            FormatTarget::Ranges(selection_ranges) => {
19037                let multi_buffer = buffer.read(cx);
19038                let snapshot = multi_buffer.read(cx);
19039                let mut buffers = HashSet::default();
19040                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19041                    BTreeMap::new();
19042                for selection_range in selection_ranges {
19043                    for (buffer, buffer_range, _) in
19044                        snapshot.range_to_buffer_ranges(selection_range.start..=selection_range.end)
19045                    {
19046                        let buffer_id = buffer.remote_id();
19047                        let start = buffer.anchor_before(buffer_range.start);
19048                        let end = buffer.anchor_after(buffer_range.end);
19049                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19050                        buffer_id_to_ranges
19051                            .entry(buffer_id)
19052                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19053                            .or_insert_with(|| vec![start..end]);
19054                    }
19055                }
19056                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19057            }
19058        };
19059
19060        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19061        let selections_prev = transaction_id_prev
19062            .and_then(|transaction_id_prev| {
19063                // default to selections as they were after the last edit, if we have them,
19064                // instead of how they are now.
19065                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19066                // will take you back to where you made the last edit, instead of staying where you scrolled
19067                self.selection_history
19068                    .transaction(transaction_id_prev)
19069                    .map(|t| t.0.clone())
19070            })
19071            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19072
19073        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19074        let format = project.update(cx, |project, cx| {
19075            project.format(buffers, target, true, trigger, cx)
19076        });
19077
19078        cx.spawn_in(window, async move |editor, cx| {
19079            let transaction = futures::select_biased! {
19080                transaction = format.log_err().fuse() => transaction,
19081                () = timeout => {
19082                    log::warn!("timed out waiting for formatting");
19083                    None
19084                }
19085            };
19086
19087            buffer.update(cx, |buffer, cx| {
19088                if let Some(transaction) = transaction
19089                    && !buffer.is_singleton()
19090                {
19091                    buffer.push_transaction(&transaction.0, cx);
19092                }
19093                cx.notify();
19094            });
19095
19096            if let Some(transaction_id_now) =
19097                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19098            {
19099                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19100                if has_new_transaction {
19101                    editor
19102                        .update(cx, |editor, _| {
19103                            editor
19104                                .selection_history
19105                                .insert_transaction(transaction_id_now, selections_prev);
19106                        })
19107                        .ok();
19108                }
19109            }
19110
19111            Ok(())
19112        })
19113    }
19114
19115    fn organize_imports(
19116        &mut self,
19117        _: &OrganizeImports,
19118        window: &mut Window,
19119        cx: &mut Context<Self>,
19120    ) -> Option<Task<Result<()>>> {
19121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19122        let project = match &self.project {
19123            Some(project) => project.clone(),
19124            None => return None,
19125        };
19126        Some(self.perform_code_action_kind(
19127            project,
19128            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19129            window,
19130            cx,
19131        ))
19132    }
19133
19134    fn perform_code_action_kind(
19135        &mut self,
19136        project: Entity<Project>,
19137        kind: CodeActionKind,
19138        window: &mut Window,
19139        cx: &mut Context<Self>,
19140    ) -> Task<Result<()>> {
19141        let buffer = self.buffer.clone();
19142        let buffers = buffer.read(cx).all_buffers();
19143        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19144        let apply_action = project.update(cx, |project, cx| {
19145            project.apply_code_action_kind(buffers, kind, true, cx)
19146        });
19147        cx.spawn_in(window, async move |_, cx| {
19148            let transaction = futures::select_biased! {
19149                () = timeout => {
19150                    log::warn!("timed out waiting for executing code action");
19151                    None
19152                }
19153                transaction = apply_action.log_err().fuse() => transaction,
19154            };
19155            buffer.update(cx, |buffer, cx| {
19156                // check if we need this
19157                if let Some(transaction) = transaction
19158                    && !buffer.is_singleton()
19159                {
19160                    buffer.push_transaction(&transaction.0, cx);
19161                }
19162                cx.notify();
19163            });
19164            Ok(())
19165        })
19166    }
19167
19168    pub fn restart_language_server(
19169        &mut self,
19170        _: &RestartLanguageServer,
19171        _: &mut Window,
19172        cx: &mut Context<Self>,
19173    ) {
19174        if let Some(project) = self.project.clone() {
19175            self.buffer.update(cx, |multi_buffer, cx| {
19176                project.update(cx, |project, cx| {
19177                    project.restart_language_servers_for_buffers(
19178                        multi_buffer.all_buffers().into_iter().collect(),
19179                        HashSet::default(),
19180                        cx,
19181                    );
19182                });
19183            })
19184        }
19185    }
19186
19187    pub fn stop_language_server(
19188        &mut self,
19189        _: &StopLanguageServer,
19190        _: &mut Window,
19191        cx: &mut Context<Self>,
19192    ) {
19193        if let Some(project) = self.project.clone() {
19194            self.buffer.update(cx, |multi_buffer, cx| {
19195                project.update(cx, |project, cx| {
19196                    project.stop_language_servers_for_buffers(
19197                        multi_buffer.all_buffers().into_iter().collect(),
19198                        HashSet::default(),
19199                        cx,
19200                    );
19201                });
19202            });
19203        }
19204    }
19205
19206    fn cancel_language_server_work(
19207        workspace: &mut Workspace,
19208        _: &actions::CancelLanguageServerWork,
19209        _: &mut Window,
19210        cx: &mut Context<Workspace>,
19211    ) {
19212        let project = workspace.project();
19213        let buffers = workspace
19214            .active_item(cx)
19215            .and_then(|item| item.act_as::<Editor>(cx))
19216            .map_or(HashSet::default(), |editor| {
19217                editor.read(cx).buffer.read(cx).all_buffers()
19218            });
19219        project.update(cx, |project, cx| {
19220            project.cancel_language_server_work_for_buffers(buffers, cx);
19221        });
19222    }
19223
19224    fn show_character_palette(
19225        &mut self,
19226        _: &ShowCharacterPalette,
19227        window: &mut Window,
19228        _: &mut Context<Self>,
19229    ) {
19230        window.show_character_palette();
19231    }
19232
19233    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19234        if !self.diagnostics_enabled() {
19235            return;
19236        }
19237
19238        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19239            let buffer = self.buffer.read(cx).snapshot(cx);
19240            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19241            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19242            let is_valid = buffer
19243                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19244                .any(|entry| {
19245                    entry.diagnostic.is_primary
19246                        && !entry.range.is_empty()
19247                        && entry.range.start == primary_range_start
19248                        && entry.diagnostic.message == active_diagnostics.active_message
19249                });
19250
19251            if !is_valid {
19252                self.dismiss_diagnostics(cx);
19253            }
19254        }
19255    }
19256
19257    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19258        match &self.active_diagnostics {
19259            ActiveDiagnostic::Group(group) => Some(group),
19260            _ => None,
19261        }
19262    }
19263
19264    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19265        if !self.diagnostics_enabled() {
19266            return;
19267        }
19268        self.dismiss_diagnostics(cx);
19269        self.active_diagnostics = ActiveDiagnostic::All;
19270    }
19271
19272    fn activate_diagnostics(
19273        &mut self,
19274        buffer_id: BufferId,
19275        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19276        window: &mut Window,
19277        cx: &mut Context<Self>,
19278    ) {
19279        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19280            return;
19281        }
19282        self.dismiss_diagnostics(cx);
19283        let snapshot = self.snapshot(window, cx);
19284        let buffer = self.buffer.read(cx).snapshot(cx);
19285        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19286            return;
19287        };
19288
19289        let diagnostic_group = buffer
19290            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19291            .collect::<Vec<_>>();
19292
19293        let language_registry = self
19294            .project()
19295            .map(|project| project.read(cx).languages().clone());
19296
19297        let blocks = renderer.render_group(
19298            diagnostic_group,
19299            buffer_id,
19300            snapshot,
19301            cx.weak_entity(),
19302            language_registry,
19303            cx,
19304        );
19305
19306        let blocks = self.display_map.update(cx, |display_map, cx| {
19307            display_map.insert_blocks(blocks, cx).into_iter().collect()
19308        });
19309        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19310            active_range: buffer.anchor_before(diagnostic.range.start)
19311                ..buffer.anchor_after(diagnostic.range.end),
19312            active_message: diagnostic.diagnostic.message.clone(),
19313            group_id: diagnostic.diagnostic.group_id,
19314            blocks,
19315        });
19316        cx.notify();
19317    }
19318
19319    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19320        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19321            return;
19322        };
19323
19324        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19325        if let ActiveDiagnostic::Group(group) = prev {
19326            self.display_map.update(cx, |display_map, cx| {
19327                display_map.remove_blocks(group.blocks, cx);
19328            });
19329            cx.notify();
19330        }
19331    }
19332
19333    /// Disable inline diagnostics rendering for this editor.
19334    pub fn disable_inline_diagnostics(&mut self) {
19335        self.inline_diagnostics_enabled = false;
19336        self.inline_diagnostics_update = Task::ready(());
19337        self.inline_diagnostics.clear();
19338    }
19339
19340    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19341        self.diagnostics_enabled = false;
19342        self.dismiss_diagnostics(cx);
19343        self.inline_diagnostics_update = Task::ready(());
19344        self.inline_diagnostics.clear();
19345    }
19346
19347    pub fn disable_word_completions(&mut self) {
19348        self.word_completions_enabled = false;
19349    }
19350
19351    pub fn diagnostics_enabled(&self) -> bool {
19352        self.diagnostics_enabled && self.mode.is_full()
19353    }
19354
19355    pub fn inline_diagnostics_enabled(&self) -> bool {
19356        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19357    }
19358
19359    pub fn show_inline_diagnostics(&self) -> bool {
19360        self.show_inline_diagnostics
19361    }
19362
19363    pub fn toggle_inline_diagnostics(
19364        &mut self,
19365        _: &ToggleInlineDiagnostics,
19366        window: &mut Window,
19367        cx: &mut Context<Editor>,
19368    ) {
19369        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19370        self.refresh_inline_diagnostics(false, window, cx);
19371    }
19372
19373    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19374        self.diagnostics_max_severity = severity;
19375        self.display_map.update(cx, |display_map, _| {
19376            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19377        });
19378    }
19379
19380    pub fn toggle_diagnostics(
19381        &mut self,
19382        _: &ToggleDiagnostics,
19383        window: &mut Window,
19384        cx: &mut Context<Editor>,
19385    ) {
19386        if !self.diagnostics_enabled() {
19387            return;
19388        }
19389
19390        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19391            EditorSettings::get_global(cx)
19392                .diagnostics_max_severity
19393                .filter(|severity| severity != &DiagnosticSeverity::Off)
19394                .unwrap_or(DiagnosticSeverity::Hint)
19395        } else {
19396            DiagnosticSeverity::Off
19397        };
19398        self.set_max_diagnostics_severity(new_severity, cx);
19399        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19400            self.active_diagnostics = ActiveDiagnostic::None;
19401            self.inline_diagnostics_update = Task::ready(());
19402            self.inline_diagnostics.clear();
19403        } else {
19404            self.refresh_inline_diagnostics(false, window, cx);
19405        }
19406
19407        cx.notify();
19408    }
19409
19410    pub fn toggle_minimap(
19411        &mut self,
19412        _: &ToggleMinimap,
19413        window: &mut Window,
19414        cx: &mut Context<Editor>,
19415    ) {
19416        if self.supports_minimap(cx) {
19417            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19418        }
19419    }
19420
19421    fn refresh_inline_diagnostics(
19422        &mut self,
19423        debounce: bool,
19424        window: &mut Window,
19425        cx: &mut Context<Self>,
19426    ) {
19427        let max_severity = ProjectSettings::get_global(cx)
19428            .diagnostics
19429            .inline
19430            .max_severity
19431            .unwrap_or(self.diagnostics_max_severity);
19432
19433        if !self.inline_diagnostics_enabled()
19434            || !self.diagnostics_enabled()
19435            || !self.show_inline_diagnostics
19436            || max_severity == DiagnosticSeverity::Off
19437        {
19438            self.inline_diagnostics_update = Task::ready(());
19439            self.inline_diagnostics.clear();
19440            return;
19441        }
19442
19443        let debounce_ms = ProjectSettings::get_global(cx)
19444            .diagnostics
19445            .inline
19446            .update_debounce_ms;
19447        let debounce = if debounce && debounce_ms > 0 {
19448            Some(Duration::from_millis(debounce_ms))
19449        } else {
19450            None
19451        };
19452        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19453            if let Some(debounce) = debounce {
19454                cx.background_executor().timer(debounce).await;
19455            }
19456            let Some(snapshot) = editor.upgrade().map(|editor| {
19457                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19458            }) else {
19459                return;
19460            };
19461
19462            let new_inline_diagnostics = cx
19463                .background_spawn(async move {
19464                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19465                    for diagnostic_entry in
19466                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19467                    {
19468                        let message = diagnostic_entry
19469                            .diagnostic
19470                            .message
19471                            .split_once('\n')
19472                            .map(|(line, _)| line)
19473                            .map(SharedString::new)
19474                            .unwrap_or_else(|| {
19475                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19476                            });
19477                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19478                        let (Ok(i) | Err(i)) = inline_diagnostics
19479                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19480                        inline_diagnostics.insert(
19481                            i,
19482                            (
19483                                start_anchor,
19484                                InlineDiagnostic {
19485                                    message,
19486                                    group_id: diagnostic_entry.diagnostic.group_id,
19487                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19488                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19489                                    severity: diagnostic_entry.diagnostic.severity,
19490                                },
19491                            ),
19492                        );
19493                    }
19494                    inline_diagnostics
19495                })
19496                .await;
19497
19498            editor
19499                .update(cx, |editor, cx| {
19500                    editor.inline_diagnostics = new_inline_diagnostics;
19501                    cx.notify();
19502                })
19503                .ok();
19504        });
19505    }
19506
19507    fn pull_diagnostics(
19508        &mut self,
19509        buffer_id: BufferId,
19510        _window: &Window,
19511        cx: &mut Context<Self>,
19512    ) -> Option<()> {
19513        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
19514        // skip any LSP updates for it.
19515
19516        if self.active_diagnostics == ActiveDiagnostic::All
19517            || !self.mode().is_full()
19518            || !self.diagnostics_enabled()
19519        {
19520            return None;
19521        }
19522        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19523            .diagnostics
19524            .lsp_pull_diagnostics;
19525        if !pull_diagnostics_settings.enabled {
19526            return None;
19527        }
19528        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19529        let project = self.project()?.downgrade();
19530        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19531
19532        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19533            cx.background_executor().timer(debounce).await;
19534            if let Ok(task) = project.update(cx, |project, cx| {
19535                project.lsp_store().update(cx, |lsp_store, cx| {
19536                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19537                })
19538            }) {
19539                task.await.log_err();
19540            }
19541            project
19542                .update(cx, |project, cx| {
19543                    project.lsp_store().update(cx, |lsp_store, cx| {
19544                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19545                    })
19546                })
19547                .log_err();
19548        });
19549
19550        Some(())
19551    }
19552
19553    pub fn set_selections_from_remote(
19554        &mut self,
19555        selections: Vec<Selection<Anchor>>,
19556        pending_selection: Option<Selection<Anchor>>,
19557        window: &mut Window,
19558        cx: &mut Context<Self>,
19559    ) {
19560        let old_cursor_position = self.selections.newest_anchor().head();
19561        self.selections
19562            .change_with(&self.display_snapshot(cx), |s| {
19563                s.select_anchors(selections);
19564                if let Some(pending_selection) = pending_selection {
19565                    s.set_pending(pending_selection, SelectMode::Character);
19566                } else {
19567                    s.clear_pending();
19568                }
19569            });
19570        self.selections_did_change(
19571            false,
19572            &old_cursor_position,
19573            SelectionEffects::default(),
19574            window,
19575            cx,
19576        );
19577    }
19578
19579    pub fn transact(
19580        &mut self,
19581        window: &mut Window,
19582        cx: &mut Context<Self>,
19583        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19584    ) -> Option<TransactionId> {
19585        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19586            this.start_transaction_at(Instant::now(), window, cx);
19587            update(this, window, cx);
19588            this.end_transaction_at(Instant::now(), cx)
19589        })
19590    }
19591
19592    pub fn start_transaction_at(
19593        &mut self,
19594        now: Instant,
19595        window: &mut Window,
19596        cx: &mut Context<Self>,
19597    ) -> Option<TransactionId> {
19598        self.end_selection(window, cx);
19599        if let Some(tx_id) = self
19600            .buffer
19601            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19602        {
19603            self.selection_history
19604                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19605            cx.emit(EditorEvent::TransactionBegun {
19606                transaction_id: tx_id,
19607            });
19608            Some(tx_id)
19609        } else {
19610            None
19611        }
19612    }
19613
19614    pub fn end_transaction_at(
19615        &mut self,
19616        now: Instant,
19617        cx: &mut Context<Self>,
19618    ) -> Option<TransactionId> {
19619        if let Some(transaction_id) = self
19620            .buffer
19621            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19622        {
19623            if let Some((_, end_selections)) =
19624                self.selection_history.transaction_mut(transaction_id)
19625            {
19626                *end_selections = Some(self.selections.disjoint_anchors_arc());
19627            } else {
19628                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19629            }
19630
19631            cx.emit(EditorEvent::Edited { transaction_id });
19632            Some(transaction_id)
19633        } else {
19634            None
19635        }
19636    }
19637
19638    pub fn modify_transaction_selection_history(
19639        &mut self,
19640        transaction_id: TransactionId,
19641        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19642    ) -> bool {
19643        self.selection_history
19644            .transaction_mut(transaction_id)
19645            .map(modify)
19646            .is_some()
19647    }
19648
19649    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19650        if self.selection_mark_mode {
19651            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19652                s.move_with(|_, sel| {
19653                    sel.collapse_to(sel.head(), SelectionGoal::None);
19654                });
19655            })
19656        }
19657        self.selection_mark_mode = true;
19658        cx.notify();
19659    }
19660
19661    pub fn swap_selection_ends(
19662        &mut self,
19663        _: &actions::SwapSelectionEnds,
19664        window: &mut Window,
19665        cx: &mut Context<Self>,
19666    ) {
19667        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19668            s.move_with(|_, sel| {
19669                if sel.start != sel.end {
19670                    sel.reversed = !sel.reversed
19671                }
19672            });
19673        });
19674        self.request_autoscroll(Autoscroll::newest(), cx);
19675        cx.notify();
19676    }
19677
19678    pub fn toggle_focus(
19679        workspace: &mut Workspace,
19680        _: &actions::ToggleFocus,
19681        window: &mut Window,
19682        cx: &mut Context<Workspace>,
19683    ) {
19684        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19685            return;
19686        };
19687        workspace.activate_item(&item, true, true, window, cx);
19688    }
19689
19690    pub fn toggle_fold(
19691        &mut self,
19692        _: &actions::ToggleFold,
19693        window: &mut Window,
19694        cx: &mut Context<Self>,
19695    ) {
19696        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19697            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19698            let selection = self.selections.newest::<Point>(&display_map);
19699
19700            let range = if selection.is_empty() {
19701                let point = selection.head().to_display_point(&display_map);
19702                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19703                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19704                    .to_point(&display_map);
19705                start..end
19706            } else {
19707                selection.range()
19708            };
19709            if display_map.folds_in_range(range).next().is_some() {
19710                self.unfold_lines(&Default::default(), window, cx)
19711            } else {
19712                self.fold(&Default::default(), window, cx)
19713            }
19714        } else {
19715            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19716            let buffer_ids: HashSet<_> = self
19717                .selections
19718                .disjoint_anchor_ranges()
19719                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19720                .collect();
19721
19722            let should_unfold = buffer_ids
19723                .iter()
19724                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19725
19726            for buffer_id in buffer_ids {
19727                if should_unfold {
19728                    self.unfold_buffer(buffer_id, cx);
19729                } else {
19730                    self.fold_buffer(buffer_id, cx);
19731                }
19732            }
19733        }
19734    }
19735
19736    pub fn toggle_fold_recursive(
19737        &mut self,
19738        _: &actions::ToggleFoldRecursive,
19739        window: &mut Window,
19740        cx: &mut Context<Self>,
19741    ) {
19742        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19743
19744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19745        let range = if selection.is_empty() {
19746            let point = selection.head().to_display_point(&display_map);
19747            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19748            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19749                .to_point(&display_map);
19750            start..end
19751        } else {
19752            selection.range()
19753        };
19754        if display_map.folds_in_range(range).next().is_some() {
19755            self.unfold_recursive(&Default::default(), window, cx)
19756        } else {
19757            self.fold_recursive(&Default::default(), window, cx)
19758        }
19759    }
19760
19761    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19762        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19763            let mut to_fold = Vec::new();
19764            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19765            let selections = self.selections.all_adjusted(&display_map);
19766
19767            for selection in selections {
19768                let range = selection.range().sorted();
19769                let buffer_start_row = range.start.row;
19770
19771                if range.start.row != range.end.row {
19772                    let mut found = false;
19773                    let mut row = range.start.row;
19774                    while row <= range.end.row {
19775                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19776                        {
19777                            found = true;
19778                            row = crease.range().end.row + 1;
19779                            to_fold.push(crease);
19780                        } else {
19781                            row += 1
19782                        }
19783                    }
19784                    if found {
19785                        continue;
19786                    }
19787                }
19788
19789                for row in (0..=range.start.row).rev() {
19790                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19791                        && crease.range().end.row >= buffer_start_row
19792                    {
19793                        to_fold.push(crease);
19794                        if row <= range.start.row {
19795                            break;
19796                        }
19797                    }
19798                }
19799            }
19800
19801            self.fold_creases(to_fold, true, window, cx);
19802        } else {
19803            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19804            let buffer_ids = self
19805                .selections
19806                .disjoint_anchor_ranges()
19807                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19808                .collect::<HashSet<_>>();
19809            for buffer_id in buffer_ids {
19810                self.fold_buffer(buffer_id, cx);
19811            }
19812        }
19813    }
19814
19815    pub fn toggle_fold_all(
19816        &mut self,
19817        _: &actions::ToggleFoldAll,
19818        window: &mut Window,
19819        cx: &mut Context<Self>,
19820    ) {
19821        let has_folds = if self.buffer.read(cx).is_singleton() {
19822            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19823            let has_folds = display_map
19824                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19825                .next()
19826                .is_some();
19827            has_folds
19828        } else {
19829            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19830            let has_folds = buffer_ids
19831                .iter()
19832                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19833            has_folds
19834        };
19835
19836        if has_folds {
19837            self.unfold_all(&actions::UnfoldAll, window, cx);
19838        } else {
19839            self.fold_all(&actions::FoldAll, window, cx);
19840        }
19841    }
19842
19843    fn fold_at_level(
19844        &mut self,
19845        fold_at: &FoldAtLevel,
19846        window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        if !self.buffer.read(cx).is_singleton() {
19850            return;
19851        }
19852
19853        let fold_at_level = fold_at.0;
19854        let snapshot = self.buffer.read(cx).snapshot(cx);
19855        let mut to_fold = Vec::new();
19856        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19857
19858        let row_ranges_to_keep: Vec<Range<u32>> = self
19859            .selections
19860            .all::<Point>(&self.display_snapshot(cx))
19861            .into_iter()
19862            .map(|sel| sel.start.row..sel.end.row)
19863            .collect();
19864
19865        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19866            while start_row < end_row {
19867                match self
19868                    .snapshot(window, cx)
19869                    .crease_for_buffer_row(MultiBufferRow(start_row))
19870                {
19871                    Some(crease) => {
19872                        let nested_start_row = crease.range().start.row + 1;
19873                        let nested_end_row = crease.range().end.row;
19874
19875                        if current_level < fold_at_level {
19876                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19877                        } else if current_level == fold_at_level {
19878                            // Fold iff there is no selection completely contained within the fold region
19879                            if !row_ranges_to_keep.iter().any(|selection| {
19880                                selection.end >= nested_start_row
19881                                    && selection.start <= nested_end_row
19882                            }) {
19883                                to_fold.push(crease);
19884                            }
19885                        }
19886
19887                        start_row = nested_end_row + 1;
19888                    }
19889                    None => start_row += 1,
19890                }
19891            }
19892        }
19893
19894        self.fold_creases(to_fold, true, window, cx);
19895    }
19896
19897    pub fn fold_at_level_1(
19898        &mut self,
19899        _: &actions::FoldAtLevel1,
19900        window: &mut Window,
19901        cx: &mut Context<Self>,
19902    ) {
19903        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19904    }
19905
19906    pub fn fold_at_level_2(
19907        &mut self,
19908        _: &actions::FoldAtLevel2,
19909        window: &mut Window,
19910        cx: &mut Context<Self>,
19911    ) {
19912        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19913    }
19914
19915    pub fn fold_at_level_3(
19916        &mut self,
19917        _: &actions::FoldAtLevel3,
19918        window: &mut Window,
19919        cx: &mut Context<Self>,
19920    ) {
19921        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19922    }
19923
19924    pub fn fold_at_level_4(
19925        &mut self,
19926        _: &actions::FoldAtLevel4,
19927        window: &mut Window,
19928        cx: &mut Context<Self>,
19929    ) {
19930        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19931    }
19932
19933    pub fn fold_at_level_5(
19934        &mut self,
19935        _: &actions::FoldAtLevel5,
19936        window: &mut Window,
19937        cx: &mut Context<Self>,
19938    ) {
19939        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19940    }
19941
19942    pub fn fold_at_level_6(
19943        &mut self,
19944        _: &actions::FoldAtLevel6,
19945        window: &mut Window,
19946        cx: &mut Context<Self>,
19947    ) {
19948        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19949    }
19950
19951    pub fn fold_at_level_7(
19952        &mut self,
19953        _: &actions::FoldAtLevel7,
19954        window: &mut Window,
19955        cx: &mut Context<Self>,
19956    ) {
19957        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19958    }
19959
19960    pub fn fold_at_level_8(
19961        &mut self,
19962        _: &actions::FoldAtLevel8,
19963        window: &mut Window,
19964        cx: &mut Context<Self>,
19965    ) {
19966        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19967    }
19968
19969    pub fn fold_at_level_9(
19970        &mut self,
19971        _: &actions::FoldAtLevel9,
19972        window: &mut Window,
19973        cx: &mut Context<Self>,
19974    ) {
19975        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19976    }
19977
19978    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19979        if self.buffer.read(cx).is_singleton() {
19980            let mut fold_ranges = Vec::new();
19981            let snapshot = self.buffer.read(cx).snapshot(cx);
19982
19983            for row in 0..snapshot.max_row().0 {
19984                if let Some(foldable_range) = self
19985                    .snapshot(window, cx)
19986                    .crease_for_buffer_row(MultiBufferRow(row))
19987                {
19988                    fold_ranges.push(foldable_range);
19989                }
19990            }
19991
19992            self.fold_creases(fold_ranges, true, window, cx);
19993        } else {
19994            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19995                editor
19996                    .update_in(cx, |editor, _, cx| {
19997                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19998                            editor.fold_buffer(buffer_id, cx);
19999                        }
20000                    })
20001                    .ok();
20002            });
20003        }
20004        cx.emit(SearchEvent::ResultsCollapsedChanged(
20005            CollapseDirection::Collapsed,
20006        ));
20007    }
20008
20009    pub fn fold_function_bodies(
20010        &mut self,
20011        _: &actions::FoldFunctionBodies,
20012        window: &mut Window,
20013        cx: &mut Context<Self>,
20014    ) {
20015        let snapshot = self.buffer.read(cx).snapshot(cx);
20016
20017        let ranges = snapshot
20018            .text_object_ranges(
20019                MultiBufferOffset(0)..snapshot.len(),
20020                TreeSitterOptions::default(),
20021            )
20022            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20023            .collect::<Vec<_>>();
20024
20025        let creases = ranges
20026            .into_iter()
20027            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20028            .collect();
20029
20030        self.fold_creases(creases, true, window, cx);
20031    }
20032
20033    pub fn fold_recursive(
20034        &mut self,
20035        _: &actions::FoldRecursive,
20036        window: &mut Window,
20037        cx: &mut Context<Self>,
20038    ) {
20039        let mut to_fold = Vec::new();
20040        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20041        let selections = self.selections.all_adjusted(&display_map);
20042
20043        for selection in selections {
20044            let range = selection.range().sorted();
20045            let buffer_start_row = range.start.row;
20046
20047            if range.start.row != range.end.row {
20048                let mut found = false;
20049                for row in range.start.row..=range.end.row {
20050                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20051                        found = true;
20052                        to_fold.push(crease);
20053                    }
20054                }
20055                if found {
20056                    continue;
20057                }
20058            }
20059
20060            for row in (0..=range.start.row).rev() {
20061                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20062                    if crease.range().end.row >= buffer_start_row {
20063                        to_fold.push(crease);
20064                    } else {
20065                        break;
20066                    }
20067                }
20068            }
20069        }
20070
20071        self.fold_creases(to_fold, true, window, cx);
20072    }
20073
20074    pub fn fold_at(
20075        &mut self,
20076        buffer_row: MultiBufferRow,
20077        window: &mut Window,
20078        cx: &mut Context<Self>,
20079    ) {
20080        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20081
20082        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20083            let autoscroll = self
20084                .selections
20085                .all::<Point>(&display_map)
20086                .iter()
20087                .any(|selection| crease.range().overlaps(&selection.range()));
20088
20089            self.fold_creases(vec![crease], autoscroll, window, cx);
20090        }
20091    }
20092
20093    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20094        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20095            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20096            let buffer = display_map.buffer_snapshot();
20097            let selections = self.selections.all::<Point>(&display_map);
20098            let ranges = selections
20099                .iter()
20100                .map(|s| {
20101                    let range = s.display_range(&display_map).sorted();
20102                    let mut start = range.start.to_point(&display_map);
20103                    let mut end = range.end.to_point(&display_map);
20104                    start.column = 0;
20105                    end.column = buffer.line_len(MultiBufferRow(end.row));
20106                    start..end
20107                })
20108                .collect::<Vec<_>>();
20109
20110            self.unfold_ranges(&ranges, true, true, cx);
20111        } else {
20112            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20113            let buffer_ids = self
20114                .selections
20115                .disjoint_anchor_ranges()
20116                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20117                .collect::<HashSet<_>>();
20118            for buffer_id in buffer_ids {
20119                self.unfold_buffer(buffer_id, cx);
20120            }
20121        }
20122    }
20123
20124    pub fn unfold_recursive(
20125        &mut self,
20126        _: &UnfoldRecursive,
20127        _window: &mut Window,
20128        cx: &mut Context<Self>,
20129    ) {
20130        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20131        let selections = self.selections.all::<Point>(&display_map);
20132        let ranges = selections
20133            .iter()
20134            .map(|s| {
20135                let mut range = s.display_range(&display_map).sorted();
20136                *range.start.column_mut() = 0;
20137                *range.end.column_mut() = display_map.line_len(range.end.row());
20138                let start = range.start.to_point(&display_map);
20139                let end = range.end.to_point(&display_map);
20140                start..end
20141            })
20142            .collect::<Vec<_>>();
20143
20144        self.unfold_ranges(&ranges, true, true, cx);
20145    }
20146
20147    pub fn unfold_at(
20148        &mut self,
20149        buffer_row: MultiBufferRow,
20150        _window: &mut Window,
20151        cx: &mut Context<Self>,
20152    ) {
20153        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20154
20155        let intersection_range = Point::new(buffer_row.0, 0)
20156            ..Point::new(
20157                buffer_row.0,
20158                display_map.buffer_snapshot().line_len(buffer_row),
20159            );
20160
20161        let autoscroll = self
20162            .selections
20163            .all::<Point>(&display_map)
20164            .iter()
20165            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20166
20167        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20168    }
20169
20170    pub fn unfold_all(
20171        &mut self,
20172        _: &actions::UnfoldAll,
20173        _window: &mut Window,
20174        cx: &mut Context<Self>,
20175    ) {
20176        if self.buffer.read(cx).is_singleton() {
20177            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20178            self.unfold_ranges(
20179                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20180                true,
20181                true,
20182                cx,
20183            );
20184        } else {
20185            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20186                editor
20187                    .update(cx, |editor, cx| {
20188                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
20189                            editor.unfold_buffer(buffer_id, cx);
20190                        }
20191                    })
20192                    .ok();
20193            });
20194        }
20195        cx.emit(SearchEvent::ResultsCollapsedChanged(
20196            CollapseDirection::Expanded,
20197        ));
20198    }
20199
20200    pub fn fold_selected_ranges(
20201        &mut self,
20202        _: &FoldSelectedRanges,
20203        window: &mut Window,
20204        cx: &mut Context<Self>,
20205    ) {
20206        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20207        let selections = self.selections.all_adjusted(&display_map);
20208        let ranges = selections
20209            .into_iter()
20210            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20211            .collect::<Vec<_>>();
20212        self.fold_creases(ranges, true, window, cx);
20213    }
20214
20215    pub fn fold_ranges<T: ToOffset + Clone>(
20216        &mut self,
20217        ranges: Vec<Range<T>>,
20218        auto_scroll: bool,
20219        window: &mut Window,
20220        cx: &mut Context<Self>,
20221    ) {
20222        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20223        let ranges = ranges
20224            .into_iter()
20225            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20226            .collect::<Vec<_>>();
20227        self.fold_creases(ranges, auto_scroll, window, cx);
20228    }
20229
20230    pub fn fold_creases<T: ToOffset + Clone>(
20231        &mut self,
20232        creases: Vec<Crease<T>>,
20233        auto_scroll: bool,
20234        _window: &mut Window,
20235        cx: &mut Context<Self>,
20236    ) {
20237        if creases.is_empty() {
20238            return;
20239        }
20240
20241        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20242
20243        if auto_scroll {
20244            self.request_autoscroll(Autoscroll::fit(), cx);
20245        }
20246
20247        cx.notify();
20248
20249        self.scrollbar_marker_state.dirty = true;
20250        self.folds_did_change(cx);
20251    }
20252
20253    /// Removes any folds whose ranges intersect any of the given ranges.
20254    pub fn unfold_ranges<T: ToOffset + Clone>(
20255        &mut self,
20256        ranges: &[Range<T>],
20257        inclusive: bool,
20258        auto_scroll: bool,
20259        cx: &mut Context<Self>,
20260    ) {
20261        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20262            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20263        });
20264        self.folds_did_change(cx);
20265    }
20266
20267    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20268        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
20269            return;
20270        }
20271
20272        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20273        self.display_map.update(cx, |display_map, cx| {
20274            display_map.fold_buffers([buffer_id], cx)
20275        });
20276
20277        let snapshot = self.display_snapshot(cx);
20278        self.selections.change_with(&snapshot, |selections| {
20279            selections.remove_selections_from_buffer(buffer_id);
20280        });
20281
20282        cx.emit(EditorEvent::BufferFoldToggled {
20283            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
20284            folded: true,
20285        });
20286        cx.notify();
20287    }
20288
20289    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20290        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20291            return;
20292        }
20293        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20294        self.display_map.update(cx, |display_map, cx| {
20295            display_map.unfold_buffers([buffer_id], cx);
20296        });
20297        cx.emit(EditorEvent::BufferFoldToggled {
20298            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
20299            folded: false,
20300        });
20301        cx.notify();
20302    }
20303
20304    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20305        self.display_map.read(cx).is_buffer_folded(buffer)
20306    }
20307
20308    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20309        self.display_map.read(cx).folded_buffers()
20310    }
20311
20312    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20313        self.display_map.update(cx, |display_map, cx| {
20314            display_map.disable_header_for_buffer(buffer_id, cx);
20315        });
20316        cx.notify();
20317    }
20318
20319    /// Removes any folds with the given ranges.
20320    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20321        &mut self,
20322        ranges: &[Range<T>],
20323        type_id: TypeId,
20324        auto_scroll: bool,
20325        cx: &mut Context<Self>,
20326    ) {
20327        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20328            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20329        });
20330        self.folds_did_change(cx);
20331    }
20332
20333    fn remove_folds_with<T: ToOffset + Clone>(
20334        &mut self,
20335        ranges: &[Range<T>],
20336        auto_scroll: bool,
20337        cx: &mut Context<Self>,
20338        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20339    ) {
20340        if ranges.is_empty() {
20341            return;
20342        }
20343
20344        let mut buffers_affected = HashSet::default();
20345        let multi_buffer = self.buffer().read(cx);
20346        for range in ranges {
20347            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
20348                buffers_affected.insert(buffer.read(cx).remote_id());
20349            };
20350        }
20351
20352        self.display_map.update(cx, update);
20353
20354        if auto_scroll {
20355            self.request_autoscroll(Autoscroll::fit(), cx);
20356        }
20357
20358        cx.notify();
20359        self.scrollbar_marker_state.dirty = true;
20360        self.active_indent_guides_state.dirty = true;
20361    }
20362
20363    pub fn update_renderer_widths(
20364        &mut self,
20365        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20366        cx: &mut Context<Self>,
20367    ) -> bool {
20368        self.display_map
20369            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20370    }
20371
20372    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20373        self.display_map.read(cx).fold_placeholder.clone()
20374    }
20375
20376    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20377        self.buffer.update(cx, |buffer, cx| {
20378            buffer.set_all_diff_hunks_expanded(cx);
20379        });
20380    }
20381
20382    pub fn expand_all_diff_hunks(
20383        &mut self,
20384        _: &ExpandAllDiffHunks,
20385        _window: &mut Window,
20386        cx: &mut Context<Self>,
20387    ) {
20388        self.buffer.update(cx, |buffer, cx| {
20389            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20390        });
20391    }
20392
20393    pub fn collapse_all_diff_hunks(
20394        &mut self,
20395        _: &CollapseAllDiffHunks,
20396        _window: &mut Window,
20397        cx: &mut Context<Self>,
20398    ) {
20399        self.buffer.update(cx, |buffer, cx| {
20400            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20401        });
20402    }
20403
20404    pub fn toggle_selected_diff_hunks(
20405        &mut self,
20406        _: &ToggleSelectedDiffHunks,
20407        _window: &mut Window,
20408        cx: &mut Context<Self>,
20409    ) {
20410        let ranges: Vec<_> = self
20411            .selections
20412            .disjoint_anchors()
20413            .iter()
20414            .map(|s| s.range())
20415            .collect();
20416        self.toggle_diff_hunks_in_ranges(ranges, cx);
20417    }
20418
20419    pub fn diff_hunks_in_ranges<'a>(
20420        &'a self,
20421        ranges: &'a [Range<Anchor>],
20422        buffer: &'a MultiBufferSnapshot,
20423    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20424        ranges.iter().flat_map(move |range| {
20425            let end_excerpt_id = range.end.excerpt_id;
20426            let range = range.to_point(buffer);
20427            let mut peek_end = range.end;
20428            if range.end.row < buffer.max_row().0 {
20429                peek_end = Point::new(range.end.row + 1, 0);
20430            }
20431            buffer
20432                .diff_hunks_in_range(range.start..peek_end)
20433                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20434        })
20435    }
20436
20437    pub fn has_stageable_diff_hunks_in_ranges(
20438        &self,
20439        ranges: &[Range<Anchor>],
20440        snapshot: &MultiBufferSnapshot,
20441    ) -> bool {
20442        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20443        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20444    }
20445
20446    pub fn toggle_staged_selected_diff_hunks(
20447        &mut self,
20448        _: &::git::ToggleStaged,
20449        _: &mut Window,
20450        cx: &mut Context<Self>,
20451    ) {
20452        let snapshot = self.buffer.read(cx).snapshot(cx);
20453        let ranges: Vec<_> = self
20454            .selections
20455            .disjoint_anchors()
20456            .iter()
20457            .map(|s| s.range())
20458            .collect();
20459        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20460        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20461    }
20462
20463    pub fn set_render_diff_hunk_controls(
20464        &mut self,
20465        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20466        cx: &mut Context<Self>,
20467    ) {
20468        self.render_diff_hunk_controls = render_diff_hunk_controls;
20469        cx.notify();
20470    }
20471
20472    pub fn stage_and_next(
20473        &mut self,
20474        _: &::git::StageAndNext,
20475        window: &mut Window,
20476        cx: &mut Context<Self>,
20477    ) {
20478        self.do_stage_or_unstage_and_next(true, window, cx);
20479    }
20480
20481    pub fn unstage_and_next(
20482        &mut self,
20483        _: &::git::UnstageAndNext,
20484        window: &mut Window,
20485        cx: &mut Context<Self>,
20486    ) {
20487        self.do_stage_or_unstage_and_next(false, window, cx);
20488    }
20489
20490    pub fn stage_or_unstage_diff_hunks(
20491        &mut self,
20492        stage: bool,
20493        ranges: Vec<Range<Anchor>>,
20494        cx: &mut Context<Self>,
20495    ) {
20496        if self.delegate_stage_and_restore {
20497            let snapshot = self.buffer.read(cx).snapshot(cx);
20498            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
20499            if !hunks.is_empty() {
20500                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
20501            }
20502            return;
20503        }
20504        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20505        cx.spawn(async move |this, cx| {
20506            task.await?;
20507            this.update(cx, |this, cx| {
20508                let snapshot = this.buffer.read(cx).snapshot(cx);
20509                let chunk_by = this
20510                    .diff_hunks_in_ranges(&ranges, &snapshot)
20511                    .chunk_by(|hunk| hunk.buffer_id);
20512                for (buffer_id, hunks) in &chunk_by {
20513                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20514                }
20515            })
20516        })
20517        .detach_and_log_err(cx);
20518    }
20519
20520    fn save_buffers_for_ranges_if_needed(
20521        &mut self,
20522        ranges: &[Range<Anchor>],
20523        cx: &mut Context<Editor>,
20524    ) -> Task<Result<()>> {
20525        let multibuffer = self.buffer.read(cx);
20526        let snapshot = multibuffer.read(cx);
20527        let buffer_ids: HashSet<_> = ranges
20528            .iter()
20529            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20530            .collect();
20531        drop(snapshot);
20532
20533        let mut buffers = HashSet::default();
20534        for buffer_id in buffer_ids {
20535            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20536                let buffer = buffer_entity.read(cx);
20537                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20538                {
20539                    buffers.insert(buffer_entity);
20540                }
20541            }
20542        }
20543
20544        if let Some(project) = &self.project {
20545            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20546        } else {
20547            Task::ready(Ok(()))
20548        }
20549    }
20550
20551    fn do_stage_or_unstage_and_next(
20552        &mut self,
20553        stage: bool,
20554        window: &mut Window,
20555        cx: &mut Context<Self>,
20556    ) {
20557        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20558
20559        if ranges.iter().any(|range| range.start != range.end) {
20560            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20561            return;
20562        }
20563
20564        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20565        let snapshot = self.snapshot(window, cx);
20566        let position = self
20567            .selections
20568            .newest::<Point>(&snapshot.display_snapshot)
20569            .head();
20570        let mut row = snapshot
20571            .buffer_snapshot()
20572            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20573            .find(|hunk| hunk.row_range.start.0 > position.row)
20574            .map(|hunk| hunk.row_range.start);
20575
20576        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20577        // Outside of the project diff editor, wrap around to the beginning.
20578        if !all_diff_hunks_expanded {
20579            row = row.or_else(|| {
20580                snapshot
20581                    .buffer_snapshot()
20582                    .diff_hunks_in_range(Point::zero()..position)
20583                    .find(|hunk| hunk.row_range.end.0 < position.row)
20584                    .map(|hunk| hunk.row_range.start)
20585            });
20586        }
20587
20588        if let Some(row) = row {
20589            let destination = Point::new(row.0, 0);
20590            let autoscroll = Autoscroll::center();
20591
20592            self.unfold_ranges(&[destination..destination], false, false, cx);
20593            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20594                s.select_ranges([destination..destination]);
20595            });
20596        }
20597    }
20598
20599    pub(crate) fn do_stage_or_unstage(
20600        &self,
20601        stage: bool,
20602        buffer_id: BufferId,
20603        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20604        cx: &mut App,
20605    ) -> Option<()> {
20606        let project = self.project()?;
20607        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20608        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20609        let buffer_snapshot = buffer.read(cx).snapshot();
20610        let file_exists = buffer_snapshot
20611            .file()
20612            .is_some_and(|file| file.disk_state().exists());
20613        diff.update(cx, |diff, cx| {
20614            diff.stage_or_unstage_hunks(
20615                stage,
20616                &hunks
20617                    .map(|hunk| buffer_diff::DiffHunk {
20618                        buffer_range: hunk.buffer_range,
20619                        // We don't need to pass in word diffs here because they're only used for rendering and
20620                        // this function changes internal state
20621                        base_word_diffs: Vec::default(),
20622                        buffer_word_diffs: Vec::default(),
20623                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20624                            ..hunk.diff_base_byte_range.end.0,
20625                        secondary_status: hunk.status.secondary,
20626                        range: Point::zero()..Point::zero(), // unused
20627                    })
20628                    .collect::<Vec<_>>(),
20629                &buffer_snapshot,
20630                file_exists,
20631                cx,
20632            )
20633        });
20634        None
20635    }
20636
20637    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20638        let ranges: Vec<_> = self
20639            .selections
20640            .disjoint_anchors()
20641            .iter()
20642            .map(|s| s.range())
20643            .collect();
20644        self.buffer
20645            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20646    }
20647
20648    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20649        self.buffer.update(cx, |buffer, cx| {
20650            let ranges = vec![Anchor::min()..Anchor::max()];
20651            if !buffer.all_diff_hunks_expanded()
20652                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20653            {
20654                buffer.collapse_diff_hunks(ranges, cx);
20655                true
20656            } else {
20657                false
20658            }
20659        })
20660    }
20661
20662    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20663        if self.buffer.read(cx).all_diff_hunks_expanded() {
20664            return true;
20665        }
20666        let ranges = vec![Anchor::min()..Anchor::max()];
20667        self.buffer
20668            .read(cx)
20669            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20670    }
20671
20672    fn toggle_diff_hunks_in_ranges(
20673        &mut self,
20674        ranges: Vec<Range<Anchor>>,
20675        cx: &mut Context<Editor>,
20676    ) {
20677        self.buffer.update(cx, |buffer, cx| {
20678            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20679            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20680        })
20681    }
20682
20683    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20684        self.buffer.update(cx, |buffer, cx| {
20685            let snapshot = buffer.snapshot(cx);
20686            let excerpt_id = range.end.excerpt_id;
20687            let point_range = range.to_point(&snapshot);
20688            let expand = !buffer.single_hunk_is_expanded(range, cx);
20689            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20690        })
20691    }
20692
20693    pub(crate) fn apply_all_diff_hunks(
20694        &mut self,
20695        _: &ApplyAllDiffHunks,
20696        window: &mut Window,
20697        cx: &mut Context<Self>,
20698    ) {
20699        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20700
20701        let buffers = self.buffer.read(cx).all_buffers();
20702        for branch_buffer in buffers {
20703            branch_buffer.update(cx, |branch_buffer, cx| {
20704                branch_buffer.merge_into_base(Vec::new(), cx);
20705            });
20706        }
20707
20708        if let Some(project) = self.project.clone() {
20709            self.save(
20710                SaveOptions {
20711                    format: true,
20712                    autosave: false,
20713                },
20714                project,
20715                window,
20716                cx,
20717            )
20718            .detach_and_log_err(cx);
20719        }
20720    }
20721
20722    pub(crate) fn apply_selected_diff_hunks(
20723        &mut self,
20724        _: &ApplyDiffHunk,
20725        window: &mut Window,
20726        cx: &mut Context<Self>,
20727    ) {
20728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20729        let snapshot = self.snapshot(window, cx);
20730        let hunks = snapshot.hunks_for_ranges(
20731            self.selections
20732                .all(&snapshot.display_snapshot)
20733                .into_iter()
20734                .map(|selection| selection.range()),
20735        );
20736        let mut ranges_by_buffer = HashMap::default();
20737        self.transact(window, cx, |editor, _window, cx| {
20738            for hunk in hunks {
20739                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20740                    ranges_by_buffer
20741                        .entry(buffer.clone())
20742                        .or_insert_with(Vec::new)
20743                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20744                }
20745            }
20746
20747            for (buffer, ranges) in ranges_by_buffer {
20748                buffer.update(cx, |buffer, cx| {
20749                    buffer.merge_into_base(ranges, cx);
20750                });
20751            }
20752        });
20753
20754        if let Some(project) = self.project.clone() {
20755            self.save(
20756                SaveOptions {
20757                    format: true,
20758                    autosave: false,
20759                },
20760                project,
20761                window,
20762                cx,
20763            )
20764            .detach_and_log_err(cx);
20765        }
20766    }
20767
20768    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20769        if hovered != self.gutter_hovered {
20770            self.gutter_hovered = hovered;
20771            cx.notify();
20772        }
20773    }
20774
20775    pub fn insert_blocks(
20776        &mut self,
20777        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20778        autoscroll: Option<Autoscroll>,
20779        cx: &mut Context<Self>,
20780    ) -> Vec<CustomBlockId> {
20781        let blocks = self
20782            .display_map
20783            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20784        if let Some(autoscroll) = autoscroll {
20785            self.request_autoscroll(autoscroll, cx);
20786        }
20787        cx.notify();
20788        blocks
20789    }
20790
20791    pub fn resize_blocks(
20792        &mut self,
20793        heights: HashMap<CustomBlockId, u32>,
20794        autoscroll: Option<Autoscroll>,
20795        cx: &mut Context<Self>,
20796    ) {
20797        self.display_map
20798            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20799        if let Some(autoscroll) = autoscroll {
20800            self.request_autoscroll(autoscroll, cx);
20801        }
20802        cx.notify();
20803    }
20804
20805    pub fn replace_blocks(
20806        &mut self,
20807        renderers: HashMap<CustomBlockId, RenderBlock>,
20808        autoscroll: Option<Autoscroll>,
20809        cx: &mut Context<Self>,
20810    ) {
20811        self.display_map
20812            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20813        if let Some(autoscroll) = autoscroll {
20814            self.request_autoscroll(autoscroll, cx);
20815        }
20816        cx.notify();
20817    }
20818
20819    pub fn remove_blocks(
20820        &mut self,
20821        block_ids: HashSet<CustomBlockId>,
20822        autoscroll: Option<Autoscroll>,
20823        cx: &mut Context<Self>,
20824    ) {
20825        self.display_map.update(cx, |display_map, cx| {
20826            display_map.remove_blocks(block_ids, cx)
20827        });
20828        if let Some(autoscroll) = autoscroll {
20829            self.request_autoscroll(autoscroll, cx);
20830        }
20831        cx.notify();
20832    }
20833
20834    pub fn row_for_block(
20835        &self,
20836        block_id: CustomBlockId,
20837        cx: &mut Context<Self>,
20838    ) -> Option<DisplayRow> {
20839        self.display_map
20840            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20841    }
20842
20843    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20844        self.focused_block = Some(focused_block);
20845    }
20846
20847    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20848        self.focused_block.take()
20849    }
20850
20851    pub fn insert_creases(
20852        &mut self,
20853        creases: impl IntoIterator<Item = Crease<Anchor>>,
20854        cx: &mut Context<Self>,
20855    ) -> Vec<CreaseId> {
20856        self.display_map
20857            .update(cx, |map, cx| map.insert_creases(creases, cx))
20858    }
20859
20860    pub fn remove_creases(
20861        &mut self,
20862        ids: impl IntoIterator<Item = CreaseId>,
20863        cx: &mut Context<Self>,
20864    ) -> Vec<(CreaseId, Range<Anchor>)> {
20865        self.display_map
20866            .update(cx, |map, cx| map.remove_creases(ids, cx))
20867    }
20868
20869    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20870        self.display_map
20871            .update(cx, |map, cx| map.snapshot(cx))
20872            .longest_row()
20873    }
20874
20875    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20876        self.display_map
20877            .update(cx, |map, cx| map.snapshot(cx))
20878            .max_point()
20879    }
20880
20881    pub fn text(&self, cx: &App) -> String {
20882        self.buffer.read(cx).read(cx).text()
20883    }
20884
20885    pub fn is_empty(&self, cx: &App) -> bool {
20886        self.buffer.read(cx).read(cx).is_empty()
20887    }
20888
20889    pub fn text_option(&self, cx: &App) -> Option<String> {
20890        let text = self.text(cx);
20891        let text = text.trim();
20892
20893        if text.is_empty() {
20894            return None;
20895        }
20896
20897        Some(text.to_string())
20898    }
20899
20900    pub fn set_text(
20901        &mut self,
20902        text: impl Into<Arc<str>>,
20903        window: &mut Window,
20904        cx: &mut Context<Self>,
20905    ) {
20906        self.transact(window, cx, |this, _, cx| {
20907            this.buffer
20908                .read(cx)
20909                .as_singleton()
20910                .expect("you can only call set_text on editors for singleton buffers")
20911                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20912        });
20913    }
20914
20915    pub fn display_text(&self, cx: &mut App) -> String {
20916        self.display_map
20917            .update(cx, |map, cx| map.snapshot(cx))
20918            .text()
20919    }
20920
20921    fn create_minimap(
20922        &self,
20923        minimap_settings: MinimapSettings,
20924        window: &mut Window,
20925        cx: &mut Context<Self>,
20926    ) -> Option<Entity<Self>> {
20927        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20928            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20929    }
20930
20931    fn initialize_new_minimap(
20932        &self,
20933        minimap_settings: MinimapSettings,
20934        window: &mut Window,
20935        cx: &mut Context<Self>,
20936    ) -> Entity<Self> {
20937        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20938        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20939
20940        let mut minimap = Editor::new_internal(
20941            EditorMode::Minimap {
20942                parent: cx.weak_entity(),
20943            },
20944            self.buffer.clone(),
20945            None,
20946            Some(self.display_map.clone()),
20947            window,
20948            cx,
20949        );
20950        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20951        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
20952        minimap.scroll_manager.clone_state(
20953            &self.scroll_manager,
20954            &my_snapshot,
20955            &minimap_snapshot,
20956            cx,
20957        );
20958        minimap.set_text_style_refinement(TextStyleRefinement {
20959            font_size: Some(MINIMAP_FONT_SIZE),
20960            font_weight: Some(MINIMAP_FONT_WEIGHT),
20961            font_family: Some(MINIMAP_FONT_FAMILY),
20962            ..Default::default()
20963        });
20964        minimap.update_minimap_configuration(minimap_settings, cx);
20965        cx.new(|_| minimap)
20966    }
20967
20968    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20969        let current_line_highlight = minimap_settings
20970            .current_line_highlight
20971            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20972        self.set_current_line_highlight(Some(current_line_highlight));
20973    }
20974
20975    pub fn minimap(&self) -> Option<&Entity<Self>> {
20976        self.minimap
20977            .as_ref()
20978            .filter(|_| self.minimap_visibility.visible())
20979    }
20980
20981    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20982        let mut wrap_guides = smallvec![];
20983
20984        if self.show_wrap_guides == Some(false) {
20985            return wrap_guides;
20986        }
20987
20988        let settings = self.buffer.read(cx).language_settings(cx);
20989        if settings.show_wrap_guides {
20990            match self.soft_wrap_mode(cx) {
20991                SoftWrap::Column(soft_wrap) => {
20992                    wrap_guides.push((soft_wrap as usize, true));
20993                }
20994                SoftWrap::Bounded(soft_wrap) => {
20995                    wrap_guides.push((soft_wrap as usize, true));
20996                }
20997                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20998            }
20999            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21000        }
21001
21002        wrap_guides
21003    }
21004
21005    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21006        let settings = self.buffer.read(cx).language_settings(cx);
21007        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21008        match mode {
21009            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21010                SoftWrap::None
21011            }
21012            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21013            language_settings::SoftWrap::PreferredLineLength => {
21014                SoftWrap::Column(settings.preferred_line_length)
21015            }
21016            language_settings::SoftWrap::Bounded => {
21017                SoftWrap::Bounded(settings.preferred_line_length)
21018            }
21019        }
21020    }
21021
21022    pub fn set_soft_wrap_mode(
21023        &mut self,
21024        mode: language_settings::SoftWrap,
21025        cx: &mut Context<Self>,
21026    ) {
21027        self.soft_wrap_mode_override = Some(mode);
21028        cx.notify();
21029    }
21030
21031    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21032        self.hard_wrap = hard_wrap;
21033        cx.notify();
21034    }
21035
21036    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21037        self.text_style_refinement = Some(style);
21038    }
21039
21040    /// called by the Element so we know what style we were most recently rendered with.
21041    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21042        // We intentionally do not inform the display map about the minimap style
21043        // so that wrapping is not recalculated and stays consistent for the editor
21044        // and its linked minimap.
21045        if !self.mode.is_minimap() {
21046            let font = style.text.font();
21047            let font_size = style.text.font_size.to_pixels(window.rem_size());
21048            let display_map = self
21049                .placeholder_display_map
21050                .as_ref()
21051                .filter(|_| self.is_empty(cx))
21052                .unwrap_or(&self.display_map);
21053
21054            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21055        }
21056        self.style = Some(style);
21057    }
21058
21059    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21060        if self.style.is_none() {
21061            self.style = Some(self.create_style(cx));
21062        }
21063        self.style.as_ref().unwrap()
21064    }
21065
21066    // Called by the element. This method is not designed to be called outside of the editor
21067    // element's layout code because it does not notify when rewrapping is computed synchronously.
21068    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21069        if self.is_empty(cx) {
21070            self.placeholder_display_map
21071                .as_ref()
21072                .map_or(false, |display_map| {
21073                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21074                })
21075        } else {
21076            self.display_map
21077                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21078        }
21079    }
21080
21081    pub fn set_soft_wrap(&mut self) {
21082        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21083    }
21084
21085    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21086        if self.soft_wrap_mode_override.is_some() {
21087            self.soft_wrap_mode_override.take();
21088        } else {
21089            let soft_wrap = match self.soft_wrap_mode(cx) {
21090                SoftWrap::GitDiff => return,
21091                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21092                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21093                    language_settings::SoftWrap::None
21094                }
21095            };
21096            self.soft_wrap_mode_override = Some(soft_wrap);
21097        }
21098        cx.notify();
21099    }
21100
21101    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21102        let Some(workspace) = self.workspace() else {
21103            return;
21104        };
21105        let fs = workspace.read(cx).app_state().fs.clone();
21106        let current_show = TabBarSettings::get_global(cx).show;
21107        update_settings_file(fs, cx, move |setting, _| {
21108            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21109        });
21110    }
21111
21112    pub fn toggle_indent_guides(
21113        &mut self,
21114        _: &ToggleIndentGuides,
21115        _: &mut Window,
21116        cx: &mut Context<Self>,
21117    ) {
21118        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21119            self.buffer
21120                .read(cx)
21121                .language_settings(cx)
21122                .indent_guides
21123                .enabled
21124        });
21125        self.show_indent_guides = Some(!currently_enabled);
21126        cx.notify();
21127    }
21128
21129    fn should_show_indent_guides(&self) -> Option<bool> {
21130        self.show_indent_guides
21131    }
21132
21133    pub fn disable_indent_guides_for_buffer(
21134        &mut self,
21135        buffer_id: BufferId,
21136        cx: &mut Context<Self>,
21137    ) {
21138        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21139        cx.notify();
21140    }
21141
21142    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21143        self.buffers_with_disabled_indent_guides
21144            .contains(&buffer_id)
21145    }
21146
21147    pub fn toggle_line_numbers(
21148        &mut self,
21149        _: &ToggleLineNumbers,
21150        _: &mut Window,
21151        cx: &mut Context<Self>,
21152    ) {
21153        let mut editor_settings = EditorSettings::get_global(cx).clone();
21154        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21155        EditorSettings::override_global(editor_settings, cx);
21156    }
21157
21158    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21159        if let Some(show_line_numbers) = self.show_line_numbers {
21160            return show_line_numbers;
21161        }
21162        EditorSettings::get_global(cx).gutter.line_numbers
21163    }
21164
21165    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21166        match (
21167            self.use_relative_line_numbers,
21168            EditorSettings::get_global(cx).relative_line_numbers,
21169        ) {
21170            (None, setting) => setting,
21171            (Some(false), _) => RelativeLineNumbers::Disabled,
21172            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21173            (Some(true), _) => RelativeLineNumbers::Enabled,
21174        }
21175    }
21176
21177    pub fn toggle_relative_line_numbers(
21178        &mut self,
21179        _: &ToggleRelativeLineNumbers,
21180        _: &mut Window,
21181        cx: &mut Context<Self>,
21182    ) {
21183        let is_relative = self.relative_line_numbers(cx);
21184        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21185    }
21186
21187    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21188        self.use_relative_line_numbers = is_relative;
21189        cx.notify();
21190    }
21191
21192    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21193        self.show_gutter = show_gutter;
21194        cx.notify();
21195    }
21196
21197    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21198        self.show_scrollbars = ScrollbarAxes {
21199            horizontal: show,
21200            vertical: show,
21201        };
21202        cx.notify();
21203    }
21204
21205    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21206        self.show_scrollbars.vertical = show;
21207        cx.notify();
21208    }
21209
21210    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21211        self.show_scrollbars.horizontal = show;
21212        cx.notify();
21213    }
21214
21215    pub fn set_minimap_visibility(
21216        &mut self,
21217        minimap_visibility: MinimapVisibility,
21218        window: &mut Window,
21219        cx: &mut Context<Self>,
21220    ) {
21221        if self.minimap_visibility != minimap_visibility {
21222            if minimap_visibility.visible() && self.minimap.is_none() {
21223                let minimap_settings = EditorSettings::get_global(cx).minimap;
21224                self.minimap =
21225                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21226            }
21227            self.minimap_visibility = minimap_visibility;
21228            cx.notify();
21229        }
21230    }
21231
21232    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21233        self.set_show_scrollbars(false, cx);
21234        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21235    }
21236
21237    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21238        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21239    }
21240
21241    /// Normally the text in full mode and auto height editors is padded on the
21242    /// left side by roughly half a character width for improved hit testing.
21243    ///
21244    /// Use this method to disable this for cases where this is not wanted (e.g.
21245    /// if you want to align the editor text with some other text above or below)
21246    /// or if you want to add this padding to single-line editors.
21247    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21248        self.offset_content = offset_content;
21249        cx.notify();
21250    }
21251
21252    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21253        self.show_line_numbers = Some(show_line_numbers);
21254        cx.notify();
21255    }
21256
21257    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21258        self.disable_expand_excerpt_buttons = true;
21259        cx.notify();
21260    }
21261
21262    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21263        self.number_deleted_lines = number;
21264        cx.notify();
21265    }
21266
21267    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21268        self.delegate_expand_excerpts = delegate;
21269    }
21270
21271    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21272        self.delegate_stage_and_restore = delegate;
21273    }
21274
21275    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21276        self.delegate_open_excerpts = delegate;
21277    }
21278
21279    pub fn set_on_local_selections_changed(
21280        &mut self,
21281        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21282    ) {
21283        self.on_local_selections_changed = callback;
21284    }
21285
21286    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21287        self.suppress_selection_callback = suppress;
21288    }
21289
21290    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21291        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21292        cx.notify();
21293    }
21294
21295    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21296        self.show_code_actions = Some(show_code_actions);
21297        cx.notify();
21298    }
21299
21300    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21301        self.show_runnables = Some(show_runnables);
21302        cx.notify();
21303    }
21304
21305    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21306        self.show_breakpoints = Some(show_breakpoints);
21307        cx.notify();
21308    }
21309
21310    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21311        self.show_diff_review_button = show;
21312        cx.notify();
21313    }
21314
21315    pub fn show_diff_review_button(&self) -> bool {
21316        self.show_diff_review_button
21317    }
21318
21319    pub fn render_diff_review_button(
21320        &self,
21321        display_row: DisplayRow,
21322        width: Pixels,
21323        cx: &mut Context<Self>,
21324    ) -> impl IntoElement {
21325        let text_color = cx.theme().colors().text;
21326        let icon_color = cx.theme().colors().icon_accent;
21327
21328        h_flex()
21329            .id("diff_review_button")
21330            .cursor_pointer()
21331            .w(width - px(1.))
21332            .h(relative(0.9))
21333            .justify_center()
21334            .rounded_sm()
21335            .border_1()
21336            .border_color(text_color.opacity(0.1))
21337            .bg(text_color.opacity(0.15))
21338            .hover(|s| {
21339                s.bg(icon_color.opacity(0.4))
21340                    .border_color(icon_color.opacity(0.5))
21341            })
21342            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21343            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21344            .on_mouse_down(
21345                gpui::MouseButton::Left,
21346                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21347                    editor.start_diff_review_drag(display_row, window, cx);
21348                }),
21349            )
21350    }
21351
21352    pub fn start_diff_review_drag(
21353        &mut self,
21354        display_row: DisplayRow,
21355        window: &mut Window,
21356        cx: &mut Context<Self>,
21357    ) {
21358        let snapshot = self.snapshot(window, cx);
21359        let point = snapshot
21360            .display_snapshot
21361            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21362        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21363        self.diff_review_drag_state = Some(DiffReviewDragState {
21364            start_anchor: anchor,
21365            current_anchor: anchor,
21366        });
21367        cx.notify();
21368    }
21369
21370    pub fn update_diff_review_drag(
21371        &mut self,
21372        display_row: DisplayRow,
21373        window: &mut Window,
21374        cx: &mut Context<Self>,
21375    ) {
21376        if self.diff_review_drag_state.is_none() {
21377            return;
21378        }
21379        let snapshot = self.snapshot(window, cx);
21380        let point = snapshot
21381            .display_snapshot
21382            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21383        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21384        if let Some(drag_state) = &mut self.diff_review_drag_state {
21385            drag_state.current_anchor = anchor;
21386            cx.notify();
21387        }
21388    }
21389
21390    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21391        if let Some(drag_state) = self.diff_review_drag_state.take() {
21392            let snapshot = self.snapshot(window, cx);
21393            let range = drag_state.row_range(&snapshot.display_snapshot);
21394            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21395        }
21396        cx.notify();
21397    }
21398
21399    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21400        self.diff_review_drag_state = None;
21401        cx.notify();
21402    }
21403
21404    /// Calculates the appropriate block height for the diff review overlay.
21405    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21406    /// and 2 lines per comment when expanded.
21407    fn calculate_overlay_height(
21408        &self,
21409        hunk_key: &DiffHunkKey,
21410        comments_expanded: bool,
21411        snapshot: &MultiBufferSnapshot,
21412    ) -> u32 {
21413        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21414        let base_height: u32 = 2; // Input row with avatar and buttons
21415
21416        if comment_count == 0 {
21417            base_height
21418        } else if comments_expanded {
21419            // Header (1 line) + 2 lines per comment
21420            base_height + 1 + (comment_count as u32 * 2)
21421        } else {
21422            // Just header when collapsed
21423            base_height + 1
21424        }
21425    }
21426
21427    pub fn show_diff_review_overlay(
21428        &mut self,
21429        display_range: Range<DisplayRow>,
21430        window: &mut Window,
21431        cx: &mut Context<Self>,
21432    ) {
21433        let Range { start, end } = display_range.sorted();
21434
21435        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21436        let editor_snapshot = self.snapshot(window, cx);
21437
21438        // Convert display rows to multibuffer points
21439        let start_point = editor_snapshot
21440            .display_snapshot
21441            .display_point_to_point(start.as_display_point(), Bias::Left);
21442        let end_point = editor_snapshot
21443            .display_snapshot
21444            .display_point_to_point(end.as_display_point(), Bias::Left);
21445        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21446
21447        // Create anchor range for the selected lines (start of first line to end of last line)
21448        let line_end = Point::new(
21449            end_point.row,
21450            buffer_snapshot.line_len(end_multi_buffer_row),
21451        );
21452        let anchor_range =
21453            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21454
21455        // Compute the hunk key for this display row
21456        let file_path = buffer_snapshot
21457            .file_at(start_point)
21458            .map(|file: &Arc<dyn language::File>| file.path().clone())
21459            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21460        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21461        let new_hunk_key = DiffHunkKey {
21462            file_path,
21463            hunk_start_anchor,
21464        };
21465
21466        // Check if we already have an overlay for this hunk
21467        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21468            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21469        }) {
21470            // Just focus the existing overlay's prompt editor
21471            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21472            window.focus(&focus_handle, cx);
21473            return;
21474        }
21475
21476        // Dismiss overlays that have no comments for their hunks
21477        self.dismiss_overlays_without_comments(cx);
21478
21479        // Get the current user's avatar URI from the project's user_store
21480        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21481            let user_store = project.read(cx).user_store();
21482            user_store
21483                .read(cx)
21484                .current_user()
21485                .map(|user| user.avatar_uri.clone())
21486        });
21487
21488        // Create anchor at the end of the last row so the block appears immediately below it
21489        // Use multibuffer coordinates for anchor creation
21490        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21491        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21492
21493        // Use the hunk key we already computed
21494        let hunk_key = new_hunk_key;
21495
21496        // Create the prompt editor for the review input
21497        let prompt_editor = cx.new(|cx| {
21498            let mut editor = Editor::single_line(window, cx);
21499            editor.set_placeholder_text("Add a review comment...", window, cx);
21500            editor
21501        });
21502
21503        // Register the Newline action on the prompt editor to submit the review
21504        let parent_editor = cx.entity().downgrade();
21505        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21506            prompt_editor.register_action({
21507                let parent_editor = parent_editor.clone();
21508                move |_: &crate::actions::Newline, window, cx| {
21509                    if let Some(editor) = parent_editor.upgrade() {
21510                        editor.update(cx, |editor, cx| {
21511                            editor.submit_diff_review_comment(window, cx);
21512                        });
21513                    }
21514                }
21515            })
21516        });
21517
21518        // Calculate initial height based on existing comments for this hunk
21519        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21520
21521        // Create the overlay block
21522        let prompt_editor_for_render = prompt_editor.clone();
21523        let hunk_key_for_render = hunk_key.clone();
21524        let editor_handle = cx.entity().downgrade();
21525        let block = BlockProperties {
21526            style: BlockStyle::Sticky,
21527            placement: BlockPlacement::Below(anchor),
21528            height: Some(initial_height),
21529            render: Arc::new(move |cx| {
21530                Self::render_diff_review_overlay(
21531                    &prompt_editor_for_render,
21532                    &hunk_key_for_render,
21533                    &editor_handle,
21534                    cx,
21535                )
21536            }),
21537            priority: 0,
21538        };
21539
21540        let block_ids = self.insert_blocks([block], None, cx);
21541        let Some(block_id) = block_ids.into_iter().next() else {
21542            log::error!("Failed to insert diff review overlay block");
21543            return;
21544        };
21545
21546        self.diff_review_overlays.push(DiffReviewOverlay {
21547            anchor_range,
21548            block_id,
21549            prompt_editor: prompt_editor.clone(),
21550            hunk_key,
21551            comments_expanded: true,
21552            inline_edit_editors: HashMap::default(),
21553            inline_edit_subscriptions: HashMap::default(),
21554            user_avatar_uri,
21555            _subscription: subscription,
21556        });
21557
21558        // Focus the prompt editor
21559        let focus_handle = prompt_editor.focus_handle(cx);
21560        window.focus(&focus_handle, cx);
21561
21562        cx.notify();
21563    }
21564
21565    /// Dismisses all diff review overlays.
21566    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21567        if self.diff_review_overlays.is_empty() {
21568            return;
21569        }
21570        let block_ids: HashSet<_> = self
21571            .diff_review_overlays
21572            .drain(..)
21573            .map(|overlay| overlay.block_id)
21574            .collect();
21575        self.remove_blocks(block_ids, None, cx);
21576        cx.notify();
21577    }
21578
21579    /// Dismisses overlays that have no comments stored for their hunks.
21580    /// Keeps overlays that have at least one comment.
21581    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21582        let snapshot = self.buffer.read(cx).snapshot(cx);
21583
21584        // First, compute which overlays have comments (to avoid borrow issues with retain)
21585        let overlays_with_comments: Vec<bool> = self
21586            .diff_review_overlays
21587            .iter()
21588            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
21589            .collect();
21590
21591        // Now collect block IDs to remove and retain overlays
21592        let mut block_ids_to_remove = HashSet::default();
21593        let mut index = 0;
21594        self.diff_review_overlays.retain(|overlay| {
21595            let has_comments = overlays_with_comments[index];
21596            index += 1;
21597            if !has_comments {
21598                block_ids_to_remove.insert(overlay.block_id);
21599            }
21600            has_comments
21601        });
21602
21603        if !block_ids_to_remove.is_empty() {
21604            self.remove_blocks(block_ids_to_remove, None, cx);
21605            cx.notify();
21606        }
21607    }
21608
21609    /// Refreshes the diff review overlay block to update its height and render function.
21610    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
21611    fn refresh_diff_review_overlay_height(
21612        &mut self,
21613        hunk_key: &DiffHunkKey,
21614        _window: &mut Window,
21615        cx: &mut Context<Self>,
21616    ) {
21617        // Extract all needed data from overlay first to avoid borrow conflicts
21618        let snapshot = self.buffer.read(cx).snapshot(cx);
21619        let (comments_expanded, block_id, prompt_editor) = {
21620            let Some(overlay) = self
21621                .diff_review_overlays
21622                .iter()
21623                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21624            else {
21625                return;
21626            };
21627
21628            (
21629                overlay.comments_expanded,
21630                overlay.block_id,
21631                overlay.prompt_editor.clone(),
21632            )
21633        };
21634
21635        // Calculate new height
21636        let snapshot = self.buffer.read(cx).snapshot(cx);
21637        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
21638
21639        // Update the block height using resize_blocks (avoids flicker)
21640        let mut heights = HashMap::default();
21641        heights.insert(block_id, new_height);
21642        self.resize_blocks(heights, None, cx);
21643
21644        // Update the render function using replace_blocks (avoids flicker)
21645        let hunk_key_for_render = hunk_key.clone();
21646        let editor_handle = cx.entity().downgrade();
21647        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
21648            Arc::new(move |cx| {
21649                Self::render_diff_review_overlay(
21650                    &prompt_editor,
21651                    &hunk_key_for_render,
21652                    &editor_handle,
21653                    cx,
21654                )
21655            });
21656
21657        let mut renderers = HashMap::default();
21658        renderers.insert(block_id, render);
21659        self.replace_blocks(renderers, None, cx);
21660    }
21661
21662    /// Action handler for SubmitDiffReviewComment.
21663    pub fn submit_diff_review_comment_action(
21664        &mut self,
21665        _: &SubmitDiffReviewComment,
21666        window: &mut Window,
21667        cx: &mut Context<Self>,
21668    ) {
21669        self.submit_diff_review_comment(window, cx);
21670    }
21671
21672    /// Stores the diff review comment locally.
21673    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
21674    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21675        // Find the overlay that currently has focus
21676        let overlay_index = self
21677            .diff_review_overlays
21678            .iter()
21679            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
21680        let Some(overlay_index) = overlay_index else {
21681            return;
21682        };
21683        let overlay = &self.diff_review_overlays[overlay_index];
21684
21685        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
21686        if comment_text.is_empty() {
21687            return;
21688        }
21689
21690        let anchor_range = overlay.anchor_range.clone();
21691        let hunk_key = overlay.hunk_key.clone();
21692
21693        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
21694
21695        // Clear the prompt editor but keep the overlay open
21696        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
21697            overlay.prompt_editor.update(cx, |editor, cx| {
21698                editor.clear(window, cx);
21699            });
21700        }
21701
21702        // Refresh the overlay to update the block height for the new comment
21703        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21704
21705        cx.notify();
21706    }
21707
21708    /// Returns the prompt editor for the diff review overlay, if one is active.
21709    /// This is primarily used for testing.
21710    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
21711        self.diff_review_overlays
21712            .first()
21713            .map(|overlay| &overlay.prompt_editor)
21714    }
21715
21716    /// Returns the line range for the first diff review overlay, if one is active.
21717    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
21718    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
21719        let overlay = self.diff_review_overlays.first()?;
21720        let snapshot = self.buffer.read(cx).snapshot(cx);
21721        let start_point = overlay.anchor_range.start.to_point(&snapshot);
21722        let end_point = overlay.anchor_range.end.to_point(&snapshot);
21723        let start_row = snapshot
21724            .point_to_buffer_point(start_point)
21725            .map(|(_, p, _)| p.row)
21726            .unwrap_or(start_point.row);
21727        let end_row = snapshot
21728            .point_to_buffer_point(end_point)
21729            .map(|(_, p, _)| p.row)
21730            .unwrap_or(end_point.row);
21731        Some((start_row, end_row))
21732    }
21733
21734    /// Sets whether the comments section is expanded in the diff review overlay.
21735    /// This is primarily used for testing.
21736    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
21737        for overlay in &mut self.diff_review_overlays {
21738            overlay.comments_expanded = expanded;
21739        }
21740        cx.notify();
21741    }
21742
21743    /// Compares two DiffHunkKeys for equality by resolving their anchors.
21744    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
21745        a.file_path == b.file_path
21746            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
21747    }
21748
21749    /// Returns comments for a specific hunk, ordered by creation time.
21750    pub fn comments_for_hunk<'a>(
21751        &'a self,
21752        key: &DiffHunkKey,
21753        snapshot: &MultiBufferSnapshot,
21754    ) -> &'a [StoredReviewComment] {
21755        let key_point = key.hunk_start_anchor.to_point(snapshot);
21756        self.stored_review_comments
21757            .iter()
21758            .find(|(k, _)| {
21759                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21760            })
21761            .map(|(_, comments)| comments.as_slice())
21762            .unwrap_or(&[])
21763    }
21764
21765    /// Returns the total count of stored review comments across all hunks.
21766    pub fn total_review_comment_count(&self) -> usize {
21767        self.stored_review_comments
21768            .iter()
21769            .map(|(_, v)| v.len())
21770            .sum()
21771    }
21772
21773    /// Returns the count of comments for a specific hunk.
21774    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
21775        let key_point = key.hunk_start_anchor.to_point(snapshot);
21776        self.stored_review_comments
21777            .iter()
21778            .find(|(k, _)| {
21779                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21780            })
21781            .map(|(_, v)| v.len())
21782            .unwrap_or(0)
21783    }
21784
21785    /// Adds a new review comment to a specific hunk.
21786    pub fn add_review_comment(
21787        &mut self,
21788        hunk_key: DiffHunkKey,
21789        comment: String,
21790        anchor_range: Range<Anchor>,
21791        cx: &mut Context<Self>,
21792    ) -> usize {
21793        let id = self.next_review_comment_id;
21794        self.next_review_comment_id += 1;
21795
21796        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
21797
21798        let snapshot = self.buffer.read(cx).snapshot(cx);
21799        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
21800
21801        // Find existing entry for this hunk or add a new one
21802        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
21803            k.file_path == hunk_key.file_path
21804                && k.hunk_start_anchor.to_point(&snapshot) == key_point
21805        }) {
21806            comments.push(stored_comment);
21807        } else {
21808            self.stored_review_comments
21809                .push((hunk_key, vec![stored_comment]));
21810        }
21811
21812        cx.emit(EditorEvent::ReviewCommentsChanged {
21813            total_count: self.total_review_comment_count(),
21814        });
21815        cx.notify();
21816        id
21817    }
21818
21819    /// Removes a review comment by ID from any hunk.
21820    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
21821        for (_, comments) in self.stored_review_comments.iter_mut() {
21822            if let Some(index) = comments.iter().position(|c| c.id == id) {
21823                comments.remove(index);
21824                cx.emit(EditorEvent::ReviewCommentsChanged {
21825                    total_count: self.total_review_comment_count(),
21826                });
21827                cx.notify();
21828                return true;
21829            }
21830        }
21831        false
21832    }
21833
21834    /// Updates a review comment's text by ID.
21835    pub fn update_review_comment(
21836        &mut self,
21837        id: usize,
21838        new_comment: String,
21839        cx: &mut Context<Self>,
21840    ) -> bool {
21841        for (_, comments) in self.stored_review_comments.iter_mut() {
21842            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21843                comment.comment = new_comment;
21844                comment.is_editing = false;
21845                cx.emit(EditorEvent::ReviewCommentsChanged {
21846                    total_count: self.total_review_comment_count(),
21847                });
21848                cx.notify();
21849                return true;
21850            }
21851        }
21852        false
21853    }
21854
21855    /// Sets a comment's editing state.
21856    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
21857        for (_, comments) in self.stored_review_comments.iter_mut() {
21858            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21859                comment.is_editing = is_editing;
21860                cx.notify();
21861                return;
21862            }
21863        }
21864    }
21865
21866    /// Takes all stored comments from all hunks, clearing the storage.
21867    /// Returns a Vec of (hunk_key, comments) pairs.
21868    pub fn take_all_review_comments(
21869        &mut self,
21870        cx: &mut Context<Self>,
21871    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
21872        // Dismiss all overlays when taking comments (e.g., when sending to agent)
21873        self.dismiss_all_diff_review_overlays(cx);
21874        let comments = std::mem::take(&mut self.stored_review_comments);
21875        // Reset the ID counter since all comments have been taken
21876        self.next_review_comment_id = 0;
21877        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
21878        cx.notify();
21879        comments
21880    }
21881
21882    /// Removes review comments whose anchors are no longer valid or whose
21883    /// associated diff hunks no longer exist.
21884    ///
21885    /// This should be called when the buffer changes to prevent orphaned comments
21886    /// from accumulating.
21887    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
21888        let snapshot = self.buffer.read(cx).snapshot(cx);
21889        let original_count = self.total_review_comment_count();
21890
21891        // Remove comments with invalid hunk anchors
21892        self.stored_review_comments
21893            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
21894
21895        // Also clean up individual comments with invalid anchor ranges
21896        for (_, comments) in &mut self.stored_review_comments {
21897            comments.retain(|comment| {
21898                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
21899            });
21900        }
21901
21902        // Remove empty hunk entries
21903        self.stored_review_comments
21904            .retain(|(_, comments)| !comments.is_empty());
21905
21906        let new_count = self.total_review_comment_count();
21907        if new_count != original_count {
21908            cx.emit(EditorEvent::ReviewCommentsChanged {
21909                total_count: new_count,
21910            });
21911            cx.notify();
21912        }
21913    }
21914
21915    /// Toggles the expanded state of the comments section in the overlay.
21916    pub fn toggle_review_comments_expanded(
21917        &mut self,
21918        _: &ToggleReviewCommentsExpanded,
21919        window: &mut Window,
21920        cx: &mut Context<Self>,
21921    ) {
21922        // Find the overlay that currently has focus, or use the first one
21923        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
21924            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
21925                overlay.comments_expanded = !overlay.comments_expanded;
21926                Some(overlay.hunk_key.clone())
21927            } else {
21928                None
21929            }
21930        });
21931
21932        // If no focused overlay found, toggle the first one
21933        let hunk_key = overlay_info.or_else(|| {
21934            self.diff_review_overlays.first_mut().map(|overlay| {
21935                overlay.comments_expanded = !overlay.comments_expanded;
21936                overlay.hunk_key.clone()
21937            })
21938        });
21939
21940        if let Some(hunk_key) = hunk_key {
21941            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21942            cx.notify();
21943        }
21944    }
21945
21946    /// Handles the EditReviewComment action - sets a comment into editing mode.
21947    pub fn edit_review_comment(
21948        &mut self,
21949        action: &EditReviewComment,
21950        window: &mut Window,
21951        cx: &mut Context<Self>,
21952    ) {
21953        let comment_id = action.id;
21954
21955        // Set the comment to editing mode
21956        self.set_comment_editing(comment_id, true, cx);
21957
21958        // Find the overlay that contains this comment and create an inline editor if needed
21959        // First, find which hunk this comment belongs to
21960        let hunk_key = self
21961            .stored_review_comments
21962            .iter()
21963            .find_map(|(key, comments)| {
21964                if comments.iter().any(|c| c.id == comment_id) {
21965                    Some(key.clone())
21966                } else {
21967                    None
21968                }
21969            });
21970
21971        let snapshot = self.buffer.read(cx).snapshot(cx);
21972        if let Some(hunk_key) = hunk_key {
21973            if let Some(overlay) = self
21974                .diff_review_overlays
21975                .iter_mut()
21976                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21977            {
21978                if let std::collections::hash_map::Entry::Vacant(entry) =
21979                    overlay.inline_edit_editors.entry(comment_id)
21980                {
21981                    // Find the comment text
21982                    let comment_text = self
21983                        .stored_review_comments
21984                        .iter()
21985                        .flat_map(|(_, comments)| comments)
21986                        .find(|c| c.id == comment_id)
21987                        .map(|c| c.comment.clone())
21988                        .unwrap_or_default();
21989
21990                    // Create inline editor
21991                    let parent_editor = cx.entity().downgrade();
21992                    let inline_editor = cx.new(|cx| {
21993                        let mut editor = Editor::single_line(window, cx);
21994                        editor.set_text(&*comment_text, window, cx);
21995                        // Select all text for easy replacement
21996                        editor.select_all(&crate::actions::SelectAll, window, cx);
21997                        editor
21998                    });
21999
22000                    // Register the Newline action to confirm the edit
22001                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22002                        inline_editor.register_action({
22003                            let parent_editor = parent_editor.clone();
22004                            move |_: &crate::actions::Newline, window, cx| {
22005                                if let Some(editor) = parent_editor.upgrade() {
22006                                    editor.update(cx, |editor, cx| {
22007                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22008                                    });
22009                                }
22010                            }
22011                        })
22012                    });
22013
22014                    // Store the subscription to keep the action handler alive
22015                    overlay
22016                        .inline_edit_subscriptions
22017                        .insert(comment_id, subscription);
22018
22019                    // Focus the inline editor
22020                    let focus_handle = inline_editor.focus_handle(cx);
22021                    window.focus(&focus_handle, cx);
22022
22023                    entry.insert(inline_editor);
22024                }
22025            }
22026        }
22027
22028        cx.notify();
22029    }
22030
22031    /// Confirms an inline edit of a review comment.
22032    pub fn confirm_edit_review_comment(
22033        &mut self,
22034        comment_id: usize,
22035        _window: &mut Window,
22036        cx: &mut Context<Self>,
22037    ) {
22038        // Get the new text from the inline editor
22039        // Find the overlay containing this comment's inline editor
22040        let snapshot = self.buffer.read(cx).snapshot(cx);
22041        let hunk_key = self
22042            .stored_review_comments
22043            .iter()
22044            .find_map(|(key, comments)| {
22045                if comments.iter().any(|c| c.id == comment_id) {
22046                    Some(key.clone())
22047                } else {
22048                    None
22049                }
22050            });
22051
22052        let new_text = hunk_key
22053            .as_ref()
22054            .and_then(|hunk_key| {
22055                self.diff_review_overlays
22056                    .iter()
22057                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22058            })
22059            .as_ref()
22060            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22061            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22062
22063        if let Some(new_text) = new_text {
22064            if !new_text.is_empty() {
22065                self.update_review_comment(comment_id, new_text, cx);
22066            }
22067        }
22068
22069        // Remove the inline editor and its subscription
22070        if let Some(hunk_key) = hunk_key {
22071            if let Some(overlay) = self
22072                .diff_review_overlays
22073                .iter_mut()
22074                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22075            {
22076                overlay.inline_edit_editors.remove(&comment_id);
22077                overlay.inline_edit_subscriptions.remove(&comment_id);
22078            }
22079        }
22080
22081        // Clear editing state
22082        self.set_comment_editing(comment_id, false, cx);
22083    }
22084
22085    /// Cancels an inline edit of a review comment.
22086    pub fn cancel_edit_review_comment(
22087        &mut self,
22088        comment_id: usize,
22089        _window: &mut Window,
22090        cx: &mut Context<Self>,
22091    ) {
22092        // Find which hunk this comment belongs to
22093        let hunk_key = self
22094            .stored_review_comments
22095            .iter()
22096            .find_map(|(key, comments)| {
22097                if comments.iter().any(|c| c.id == comment_id) {
22098                    Some(key.clone())
22099                } else {
22100                    None
22101                }
22102            });
22103
22104        // Remove the inline editor and its subscription
22105        if let Some(hunk_key) = hunk_key {
22106            let snapshot = self.buffer.read(cx).snapshot(cx);
22107            if let Some(overlay) = self
22108                .diff_review_overlays
22109                .iter_mut()
22110                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22111            {
22112                overlay.inline_edit_editors.remove(&comment_id);
22113                overlay.inline_edit_subscriptions.remove(&comment_id);
22114            }
22115        }
22116
22117        // Clear editing state
22118        self.set_comment_editing(comment_id, false, cx);
22119    }
22120
22121    /// Action handler for ConfirmEditReviewComment.
22122    pub fn confirm_edit_review_comment_action(
22123        &mut self,
22124        action: &ConfirmEditReviewComment,
22125        window: &mut Window,
22126        cx: &mut Context<Self>,
22127    ) {
22128        self.confirm_edit_review_comment(action.id, window, cx);
22129    }
22130
22131    /// Action handler for CancelEditReviewComment.
22132    pub fn cancel_edit_review_comment_action(
22133        &mut self,
22134        action: &CancelEditReviewComment,
22135        window: &mut Window,
22136        cx: &mut Context<Self>,
22137    ) {
22138        self.cancel_edit_review_comment(action.id, window, cx);
22139    }
22140
22141    /// Handles the DeleteReviewComment action - removes a comment.
22142    pub fn delete_review_comment(
22143        &mut self,
22144        action: &DeleteReviewComment,
22145        window: &mut Window,
22146        cx: &mut Context<Self>,
22147    ) {
22148        // Get the hunk key before removing the comment
22149        // Find the hunk key from the comment itself
22150        let comment_id = action.id;
22151        let hunk_key = self
22152            .stored_review_comments
22153            .iter()
22154            .find_map(|(key, comments)| {
22155                if comments.iter().any(|c| c.id == comment_id) {
22156                    Some(key.clone())
22157                } else {
22158                    None
22159                }
22160            });
22161
22162        // Also get it from the overlay for refresh purposes
22163        let overlay_hunk_key = self
22164            .diff_review_overlays
22165            .first()
22166            .map(|o| o.hunk_key.clone());
22167
22168        self.remove_review_comment(action.id, cx);
22169
22170        // Refresh the overlay height after removing a comment
22171        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22172            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22173        }
22174    }
22175
22176    fn render_diff_review_overlay(
22177        prompt_editor: &Entity<Editor>,
22178        hunk_key: &DiffHunkKey,
22179        editor_handle: &WeakEntity<Editor>,
22180        cx: &mut BlockContext,
22181    ) -> AnyElement {
22182        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22183            if ranges.is_empty() {
22184                return None;
22185            }
22186            let formatted: Vec<String> = ranges
22187                .iter()
22188                .map(|(start, end)| {
22189                    let start_line = start + 1;
22190                    let end_line = end + 1;
22191                    if start_line == end_line {
22192                        format!("Line {start_line}")
22193                    } else {
22194                        format!("Lines {start_line}-{end_line}")
22195                    }
22196                })
22197                .collect();
22198            // Don't show label for single line in single excerpt
22199            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22200                return None;
22201            }
22202            Some(formatted.join(""))
22203        }
22204
22205        let theme = cx.theme();
22206        let colors = theme.colors();
22207
22208        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22209            editor_handle
22210                .upgrade()
22211                .map(|editor| {
22212                    let editor = editor.read(cx);
22213                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22214                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22215                    let (expanded, editors, avatar_uri, line_ranges) = editor
22216                        .diff_review_overlays
22217                        .iter()
22218                        .find(|overlay| {
22219                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22220                        })
22221                        .map(|o| {
22222                            let start_point = o.anchor_range.start.to_point(&snapshot);
22223                            let end_point = o.anchor_range.end.to_point(&snapshot);
22224                            // Get line ranges per excerpt to detect discontinuities
22225                            let buffer_ranges =
22226                                snapshot.range_to_buffer_ranges(start_point..end_point);
22227                            let ranges: Vec<(u32, u32)> = buffer_ranges
22228                                .iter()
22229                                .map(|(buffer, range, _)| {
22230                                    let start = buffer.offset_to_point(range.start.0).row;
22231                                    let end = buffer.offset_to_point(range.end.0).row;
22232                                    (start, end)
22233                                })
22234                                .collect();
22235                            (
22236                                o.comments_expanded,
22237                                o.inline_edit_editors.clone(),
22238                                o.user_avatar_uri.clone(),
22239                                if ranges.is_empty() {
22240                                    None
22241                                } else {
22242                                    Some(ranges)
22243                                },
22244                            )
22245                        })
22246                        .unwrap_or((true, HashMap::default(), None, None));
22247                    (comments, expanded, editors, avatar_uri, line_ranges)
22248                })
22249                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22250
22251        let comment_count = comments.len();
22252        let avatar_size = px(20.);
22253        let action_icon_size = IconSize::XSmall;
22254
22255        v_flex()
22256            .w_full()
22257            .bg(colors.editor_background)
22258            .border_b_1()
22259            .border_color(colors.border)
22260            .px_2()
22261            .pb_2()
22262            .gap_2()
22263            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22264            .when_some(line_ranges, |el, ranges| {
22265                let label = format_line_ranges(&ranges);
22266                if let Some(label) = label {
22267                    el.child(
22268                        h_flex()
22269                            .w_full()
22270                            .px_2()
22271                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22272                    )
22273                } else {
22274                    el
22275                }
22276            })
22277            // Top row: editable input with user's avatar
22278            .child(
22279                h_flex()
22280                    .w_full()
22281                    .items_center()
22282                    .gap_2()
22283                    .px_2()
22284                    .py_1p5()
22285                    .rounded_md()
22286                    .bg(colors.surface_background)
22287                    .child(
22288                        div()
22289                            .size(avatar_size)
22290                            .flex_shrink_0()
22291                            .rounded_full()
22292                            .overflow_hidden()
22293                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22294                                Avatar::new(avatar_uri.clone())
22295                                    .size(avatar_size)
22296                                    .into_any_element()
22297                            } else {
22298                                Icon::new(IconName::Person)
22299                                    .size(IconSize::Small)
22300                                    .color(ui::Color::Muted)
22301                                    .into_any_element()
22302                            }),
22303                    )
22304                    .child(
22305                        div()
22306                            .flex_1()
22307                            .border_1()
22308                            .border_color(colors.border)
22309                            .rounded_md()
22310                            .bg(colors.editor_background)
22311                            .px_2()
22312                            .py_1()
22313                            .child(prompt_editor.clone()),
22314                    )
22315                    .child(
22316                        h_flex()
22317                            .flex_shrink_0()
22318                            .gap_1()
22319                            .child(
22320                                IconButton::new("diff-review-close", IconName::Close)
22321                                    .icon_color(ui::Color::Muted)
22322                                    .icon_size(action_icon_size)
22323                                    .tooltip(Tooltip::text("Close"))
22324                                    .on_click(|_, window, cx| {
22325                                        window
22326                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22327                                    }),
22328                            )
22329                            .child(
22330                                IconButton::new("diff-review-add", IconName::Return)
22331                                    .icon_color(ui::Color::Muted)
22332                                    .icon_size(action_icon_size)
22333                                    .tooltip(Tooltip::text("Add comment"))
22334                                    .on_click(|_, window, cx| {
22335                                        window.dispatch_action(
22336                                            Box::new(crate::actions::SubmitDiffReviewComment),
22337                                            cx,
22338                                        );
22339                                    }),
22340                            ),
22341                    ),
22342            )
22343            // Expandable comments section (only shown when there are comments)
22344            .when(comment_count > 0, |el| {
22345                el.child(Self::render_comments_section(
22346                    comments,
22347                    comments_expanded,
22348                    inline_editors,
22349                    user_avatar_uri,
22350                    avatar_size,
22351                    action_icon_size,
22352                    colors,
22353                ))
22354            })
22355            .into_any_element()
22356    }
22357
22358    fn render_comments_section(
22359        comments: Vec<StoredReviewComment>,
22360        expanded: bool,
22361        inline_editors: HashMap<usize, Entity<Editor>>,
22362        user_avatar_uri: Option<SharedUri>,
22363        avatar_size: Pixels,
22364        action_icon_size: IconSize,
22365        colors: &theme::ThemeColors,
22366    ) -> impl IntoElement {
22367        let comment_count = comments.len();
22368
22369        v_flex()
22370            .w_full()
22371            .gap_1()
22372            // Header with expand/collapse toggle
22373            .child(
22374                h_flex()
22375                    .id("review-comments-header")
22376                    .w_full()
22377                    .items_center()
22378                    .gap_1()
22379                    .px_2()
22380                    .py_1()
22381                    .cursor_pointer()
22382                    .rounded_md()
22383                    .hover(|style| style.bg(colors.ghost_element_hover))
22384                    .on_click(|_, window: &mut Window, cx| {
22385                        window.dispatch_action(
22386                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22387                            cx,
22388                        );
22389                    })
22390                    .child(
22391                        Icon::new(if expanded {
22392                            IconName::ChevronDown
22393                        } else {
22394                            IconName::ChevronRight
22395                        })
22396                        .size(IconSize::Small)
22397                        .color(ui::Color::Muted),
22398                    )
22399                    .child(
22400                        Label::new(format!(
22401                            "{} Comment{}",
22402                            comment_count,
22403                            if comment_count == 1 { "" } else { "s" }
22404                        ))
22405                        .size(LabelSize::Small)
22406                        .color(Color::Muted),
22407                    ),
22408            )
22409            // Comments list (when expanded)
22410            .when(expanded, |el| {
22411                el.children(comments.into_iter().map(|comment| {
22412                    let inline_editor = inline_editors.get(&comment.id).cloned();
22413                    Self::render_comment_row(
22414                        comment,
22415                        inline_editor,
22416                        user_avatar_uri.clone(),
22417                        avatar_size,
22418                        action_icon_size,
22419                        colors,
22420                    )
22421                }))
22422            })
22423    }
22424
22425    fn render_comment_row(
22426        comment: StoredReviewComment,
22427        inline_editor: Option<Entity<Editor>>,
22428        user_avatar_uri: Option<SharedUri>,
22429        avatar_size: Pixels,
22430        action_icon_size: IconSize,
22431        colors: &theme::ThemeColors,
22432    ) -> impl IntoElement {
22433        let comment_id = comment.id;
22434        let is_editing = inline_editor.is_some();
22435
22436        h_flex()
22437            .w_full()
22438            .items_center()
22439            .gap_2()
22440            .px_2()
22441            .py_1p5()
22442            .rounded_md()
22443            .bg(colors.surface_background)
22444            .child(
22445                div()
22446                    .size(avatar_size)
22447                    .flex_shrink_0()
22448                    .rounded_full()
22449                    .overflow_hidden()
22450                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22451                        Avatar::new(avatar_uri.clone())
22452                            .size(avatar_size)
22453                            .into_any_element()
22454                    } else {
22455                        Icon::new(IconName::Person)
22456                            .size(IconSize::Small)
22457                            .color(ui::Color::Muted)
22458                            .into_any_element()
22459                    }),
22460            )
22461            .child(if let Some(editor) = inline_editor {
22462                // Inline edit mode: show an editable text field
22463                div()
22464                    .flex_1()
22465                    .border_1()
22466                    .border_color(colors.border)
22467                    .rounded_md()
22468                    .bg(colors.editor_background)
22469                    .px_2()
22470                    .py_1()
22471                    .child(editor)
22472                    .into_any_element()
22473            } else {
22474                // Display mode: show the comment text
22475                div()
22476                    .flex_1()
22477                    .text_sm()
22478                    .text_color(colors.text)
22479                    .child(comment.comment)
22480                    .into_any_element()
22481            })
22482            .child(if is_editing {
22483                // Editing mode: show close and confirm buttons
22484                h_flex()
22485                    .gap_1()
22486                    .child(
22487                        IconButton::new(
22488                            format!("diff-review-cancel-edit-{comment_id}"),
22489                            IconName::Close,
22490                        )
22491                        .icon_color(ui::Color::Muted)
22492                        .icon_size(action_icon_size)
22493                        .tooltip(Tooltip::text("Cancel"))
22494                        .on_click(move |_, window, cx| {
22495                            window.dispatch_action(
22496                                Box::new(crate::actions::CancelEditReviewComment {
22497                                    id: comment_id,
22498                                }),
22499                                cx,
22500                            );
22501                        }),
22502                    )
22503                    .child(
22504                        IconButton::new(
22505                            format!("diff-review-confirm-edit-{comment_id}"),
22506                            IconName::Return,
22507                        )
22508                        .icon_color(ui::Color::Muted)
22509                        .icon_size(action_icon_size)
22510                        .tooltip(Tooltip::text("Confirm"))
22511                        .on_click(move |_, window, cx| {
22512                            window.dispatch_action(
22513                                Box::new(crate::actions::ConfirmEditReviewComment {
22514                                    id: comment_id,
22515                                }),
22516                                cx,
22517                            );
22518                        }),
22519                    )
22520                    .into_any_element()
22521            } else {
22522                // Display mode: no action buttons for now (edit/delete not yet implemented)
22523                gpui::Empty.into_any_element()
22524            })
22525    }
22526
22527    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22528        if self.display_map.read(cx).masked != masked {
22529            self.display_map.update(cx, |map, _| map.masked = masked);
22530        }
22531        cx.notify()
22532    }
22533
22534    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22535        self.show_wrap_guides = Some(show_wrap_guides);
22536        cx.notify();
22537    }
22538
22539    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22540        self.show_indent_guides = Some(show_indent_guides);
22541        cx.notify();
22542    }
22543
22544    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22545        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22546            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22547                && let Some(dir) = file.abs_path(cx).parent()
22548            {
22549                return Some(dir.to_owned());
22550            }
22551        }
22552
22553        None
22554    }
22555
22556    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22557        self.active_excerpt(cx)?
22558            .1
22559            .read(cx)
22560            .file()
22561            .and_then(|f| f.as_local())
22562    }
22563
22564    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22565        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22566            let buffer = buffer.read(cx);
22567            if let Some(project_path) = buffer.project_path(cx) {
22568                let project = self.project()?.read(cx);
22569                project.absolute_path(&project_path, cx)
22570            } else {
22571                buffer
22572                    .file()
22573                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22574            }
22575        })
22576    }
22577
22578    pub fn reveal_in_finder(
22579        &mut self,
22580        _: &RevealInFileManager,
22581        _window: &mut Window,
22582        cx: &mut Context<Self>,
22583    ) {
22584        if let Some(path) = self.target_file_abs_path(cx) {
22585            if let Some(project) = self.project() {
22586                project.update(cx, |project, cx| project.reveal_path(&path, cx));
22587            } else {
22588                cx.reveal_path(&path);
22589            }
22590        }
22591    }
22592
22593    pub fn copy_path(
22594        &mut self,
22595        _: &zed_actions::workspace::CopyPath,
22596        _window: &mut Window,
22597        cx: &mut Context<Self>,
22598    ) {
22599        if let Some(path) = self.target_file_abs_path(cx)
22600            && let Some(path) = path.to_str()
22601        {
22602            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22603        } else {
22604            cx.propagate();
22605        }
22606    }
22607
22608    pub fn copy_relative_path(
22609        &mut self,
22610        _: &zed_actions::workspace::CopyRelativePath,
22611        _window: &mut Window,
22612        cx: &mut Context<Self>,
22613    ) {
22614        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22615            let project = self.project()?.read(cx);
22616            let path = buffer.read(cx).file()?.path();
22617            let path = path.display(project.path_style(cx));
22618            Some(path)
22619        }) {
22620            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22621        } else {
22622            cx.propagate();
22623        }
22624    }
22625
22626    /// Returns the project path for the editor's buffer, if any buffer is
22627    /// opened in the editor.
22628    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
22629        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
22630            buffer.read(cx).project_path(cx)
22631        } else {
22632            None
22633        }
22634    }
22635
22636    // Returns true if the editor handled a go-to-line request
22637    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
22638        maybe!({
22639            let breakpoint_store = self.breakpoint_store.as_ref()?;
22640
22641            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
22642            else {
22643                self.clear_row_highlights::<ActiveDebugLine>();
22644                return None;
22645            };
22646
22647            let position = active_stack_frame.position;
22648            let buffer_id = position.buffer_id?;
22649            let snapshot = self
22650                .project
22651                .as_ref()?
22652                .read(cx)
22653                .buffer_for_id(buffer_id, cx)?
22654                .read(cx)
22655                .snapshot();
22656
22657            let mut handled = false;
22658            for (id, ExcerptRange { context, .. }) in
22659                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
22660            {
22661                if context.start.cmp(&position, &snapshot).is_ge()
22662                    || context.end.cmp(&position, &snapshot).is_lt()
22663                {
22664                    continue;
22665                }
22666                let snapshot = self.buffer.read(cx).snapshot(cx);
22667                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
22668
22669                handled = true;
22670                self.clear_row_highlights::<ActiveDebugLine>();
22671
22672                self.go_to_line::<ActiveDebugLine>(
22673                    multibuffer_anchor,
22674                    Some(cx.theme().colors().editor_debugger_active_line_background),
22675                    window,
22676                    cx,
22677                );
22678
22679                cx.notify();
22680            }
22681
22682            handled.then_some(())
22683        })
22684        .is_some()
22685    }
22686
22687    pub fn copy_file_name_without_extension(
22688        &mut self,
22689        _: &CopyFileNameWithoutExtension,
22690        _: &mut Window,
22691        cx: &mut Context<Self>,
22692    ) {
22693        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22694            let file = buffer.read(cx).file()?;
22695            file.path().file_stem()
22696        }) {
22697            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
22698        }
22699    }
22700
22701    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
22702        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22703            let file = buffer.read(cx).file()?;
22704            Some(file.file_name(cx))
22705        }) {
22706            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
22707        }
22708    }
22709
22710    pub fn toggle_git_blame(
22711        &mut self,
22712        _: &::git::Blame,
22713        window: &mut Window,
22714        cx: &mut Context<Self>,
22715    ) {
22716        self.show_git_blame_gutter = !self.show_git_blame_gutter;
22717
22718        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
22719            self.start_git_blame(true, window, cx);
22720        }
22721
22722        cx.notify();
22723    }
22724
22725    pub fn toggle_git_blame_inline(
22726        &mut self,
22727        _: &ToggleGitBlameInline,
22728        window: &mut Window,
22729        cx: &mut Context<Self>,
22730    ) {
22731        self.toggle_git_blame_inline_internal(true, window, cx);
22732        cx.notify();
22733    }
22734
22735    pub fn open_git_blame_commit(
22736        &mut self,
22737        _: &OpenGitBlameCommit,
22738        window: &mut Window,
22739        cx: &mut Context<Self>,
22740    ) {
22741        self.open_git_blame_commit_internal(window, cx);
22742    }
22743
22744    fn open_git_blame_commit_internal(
22745        &mut self,
22746        window: &mut Window,
22747        cx: &mut Context<Self>,
22748    ) -> Option<()> {
22749        let blame = self.blame.as_ref()?;
22750        let snapshot = self.snapshot(window, cx);
22751        let cursor = self
22752            .selections
22753            .newest::<Point>(&snapshot.display_snapshot)
22754            .head();
22755        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
22756        let (_, blame_entry) = blame
22757            .update(cx, |blame, cx| {
22758                blame
22759                    .blame_for_rows(
22760                        &[RowInfo {
22761                            buffer_id: Some(buffer.remote_id()),
22762                            buffer_row: Some(point.row),
22763                            ..Default::default()
22764                        }],
22765                        cx,
22766                    )
22767                    .next()
22768            })
22769            .flatten()?;
22770        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22771        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
22772        let workspace = self.workspace()?.downgrade();
22773        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
22774        None
22775    }
22776
22777    pub fn git_blame_inline_enabled(&self) -> bool {
22778        self.git_blame_inline_enabled
22779    }
22780
22781    pub fn toggle_selection_menu(
22782        &mut self,
22783        _: &ToggleSelectionMenu,
22784        _: &mut Window,
22785        cx: &mut Context<Self>,
22786    ) {
22787        self.show_selection_menu = self
22788            .show_selection_menu
22789            .map(|show_selections_menu| !show_selections_menu)
22790            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
22791
22792        cx.notify();
22793    }
22794
22795    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
22796        self.show_selection_menu
22797            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
22798    }
22799
22800    fn start_git_blame(
22801        &mut self,
22802        user_triggered: bool,
22803        window: &mut Window,
22804        cx: &mut Context<Self>,
22805    ) {
22806        if let Some(project) = self.project() {
22807            if let Some(buffer) = self.buffer().read(cx).as_singleton()
22808                && buffer.read(cx).file().is_none()
22809            {
22810                return;
22811            }
22812
22813            let focused = self.focus_handle(cx).contains_focused(window, cx);
22814
22815            let project = project.clone();
22816            let blame = cx
22817                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
22818            self.blame_subscription =
22819                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
22820            self.blame = Some(blame);
22821        }
22822    }
22823
22824    fn toggle_git_blame_inline_internal(
22825        &mut self,
22826        user_triggered: bool,
22827        window: &mut Window,
22828        cx: &mut Context<Self>,
22829    ) {
22830        if self.git_blame_inline_enabled {
22831            self.git_blame_inline_enabled = false;
22832            self.show_git_blame_inline = false;
22833            self.show_git_blame_inline_delay_task.take();
22834        } else {
22835            self.git_blame_inline_enabled = true;
22836            self.start_git_blame_inline(user_triggered, window, cx);
22837        }
22838
22839        cx.notify();
22840    }
22841
22842    fn start_git_blame_inline(
22843        &mut self,
22844        user_triggered: bool,
22845        window: &mut Window,
22846        cx: &mut Context<Self>,
22847    ) {
22848        self.start_git_blame(user_triggered, window, cx);
22849
22850        if ProjectSettings::get_global(cx)
22851            .git
22852            .inline_blame_delay()
22853            .is_some()
22854        {
22855            self.start_inline_blame_timer(window, cx);
22856        } else {
22857            self.show_git_blame_inline = true
22858        }
22859    }
22860
22861    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
22862        self.blame.as_ref()
22863    }
22864
22865    pub fn show_git_blame_gutter(&self) -> bool {
22866        self.show_git_blame_gutter
22867    }
22868
22869    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
22870        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
22871    }
22872
22873    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
22874        self.show_git_blame_inline
22875            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
22876            && !self.newest_selection_head_on_empty_line(cx)
22877            && self.has_blame_entries(cx)
22878    }
22879
22880    fn has_blame_entries(&self, cx: &App) -> bool {
22881        self.blame()
22882            .is_some_and(|blame| blame.read(cx).has_generated_entries())
22883    }
22884
22885    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
22886        let cursor_anchor = self.selections.newest_anchor().head();
22887
22888        let snapshot = self.buffer.read(cx).snapshot(cx);
22889        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
22890
22891        snapshot.line_len(buffer_row) == 0
22892    }
22893
22894    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
22895        let buffer_and_selection = maybe!({
22896            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
22897            let selection_range = selection.range();
22898
22899            let multi_buffer = self.buffer().read(cx);
22900            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
22901            let buffer_ranges = multi_buffer_snapshot
22902                .range_to_buffer_ranges(selection_range.start..=selection_range.end);
22903
22904            let (buffer, range, _) = if selection.reversed {
22905                buffer_ranges.first()
22906            } else {
22907                buffer_ranges.last()
22908            }?;
22909
22910            let buffer_range = range.to_point(buffer);
22911
22912            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
22913                return Some((
22914                    multi_buffer.buffer(buffer.remote_id()).unwrap(),
22915                    buffer_range.start.row..buffer_range.end.row,
22916                ));
22917            };
22918
22919            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
22920            let start =
22921                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.start, buffer);
22922            let end =
22923                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.end, buffer);
22924
22925            Some((
22926                multi_buffer.buffer(buffer.remote_id()).unwrap(),
22927                start.row..end.row,
22928            ))
22929        });
22930
22931        let Some((buffer, selection)) = buffer_and_selection else {
22932            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
22933        };
22934
22935        let Some(project) = self.project() else {
22936            return Task::ready(Err(anyhow!("editor does not have project")));
22937        };
22938
22939        project.update(cx, |project, cx| {
22940            project.get_permalink_to_line(&buffer, selection, cx)
22941        })
22942    }
22943
22944    pub fn copy_permalink_to_line(
22945        &mut self,
22946        _: &CopyPermalinkToLine,
22947        window: &mut Window,
22948        cx: &mut Context<Self>,
22949    ) {
22950        let permalink_task = self.get_permalink_to_line(cx);
22951        let workspace = self.workspace();
22952
22953        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22954            Ok(permalink) => {
22955                cx.update(|_, cx| {
22956                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
22957                })
22958                .ok();
22959            }
22960            Err(err) => {
22961                let message = format!("Failed to copy permalink: {err}");
22962
22963                anyhow::Result::<()>::Err(err).log_err();
22964
22965                if let Some(workspace) = workspace {
22966                    workspace
22967                        .update_in(cx, |workspace, _, cx| {
22968                            struct CopyPermalinkToLine;
22969
22970                            workspace.show_toast(
22971                                Toast::new(
22972                                    NotificationId::unique::<CopyPermalinkToLine>(),
22973                                    message,
22974                                ),
22975                                cx,
22976                            )
22977                        })
22978                        .ok();
22979                }
22980            }
22981        })
22982        .detach();
22983    }
22984
22985    pub fn copy_file_location(
22986        &mut self,
22987        _: &CopyFileLocation,
22988        _: &mut Window,
22989        cx: &mut Context<Self>,
22990    ) {
22991        let selection = self
22992            .selections
22993            .newest::<Point>(&self.display_snapshot(cx))
22994            .start
22995            .row
22996            + 1;
22997        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22998            let project = self.project()?.read(cx);
22999            let file = buffer.read(cx).file()?;
23000            let path = file.path().display(project.path_style(cx));
23001
23002            Some(format!("{path}:{selection}"))
23003        }) {
23004            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23005        }
23006    }
23007
23008    pub fn open_permalink_to_line(
23009        &mut self,
23010        _: &OpenPermalinkToLine,
23011        window: &mut Window,
23012        cx: &mut Context<Self>,
23013    ) {
23014        let permalink_task = self.get_permalink_to_line(cx);
23015        let workspace = self.workspace();
23016
23017        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23018            Ok(permalink) => {
23019                cx.update(|_, cx| {
23020                    cx.open_url(permalink.as_ref());
23021                })
23022                .ok();
23023            }
23024            Err(err) => {
23025                let message = format!("Failed to open permalink: {err}");
23026
23027                anyhow::Result::<()>::Err(err).log_err();
23028
23029                if let Some(workspace) = workspace {
23030                    workspace.update(cx, |workspace, cx| {
23031                        struct OpenPermalinkToLine;
23032
23033                        workspace.show_toast(
23034                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23035                            cx,
23036                        )
23037                    });
23038                }
23039            }
23040        })
23041        .detach();
23042    }
23043
23044    pub fn insert_uuid_v4(
23045        &mut self,
23046        _: &InsertUuidV4,
23047        window: &mut Window,
23048        cx: &mut Context<Self>,
23049    ) {
23050        self.insert_uuid(UuidVersion::V4, window, cx);
23051    }
23052
23053    pub fn insert_uuid_v7(
23054        &mut self,
23055        _: &InsertUuidV7,
23056        window: &mut Window,
23057        cx: &mut Context<Self>,
23058    ) {
23059        self.insert_uuid(UuidVersion::V7, window, cx);
23060    }
23061
23062    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23064        self.transact(window, cx, |this, window, cx| {
23065            let edits = this
23066                .selections
23067                .all::<Point>(&this.display_snapshot(cx))
23068                .into_iter()
23069                .map(|selection| {
23070                    let uuid = match version {
23071                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23072                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23073                    };
23074
23075                    (selection.range(), uuid.to_string())
23076                });
23077            this.edit(edits, cx);
23078            this.refresh_edit_prediction(true, false, window, cx);
23079        });
23080    }
23081
23082    pub fn open_selections_in_multibuffer(
23083        &mut self,
23084        _: &OpenSelectionsInMultibuffer,
23085        window: &mut Window,
23086        cx: &mut Context<Self>,
23087    ) {
23088        let multibuffer = self.buffer.read(cx);
23089
23090        let Some(buffer) = multibuffer.as_singleton() else {
23091            return;
23092        };
23093
23094        let Some(workspace) = self.workspace() else {
23095            return;
23096        };
23097
23098        let title = multibuffer.title(cx).to_string();
23099
23100        let locations = self
23101            .selections
23102            .all_anchors(&self.display_snapshot(cx))
23103            .iter()
23104            .map(|selection| {
23105                (
23106                    buffer.clone(),
23107                    (selection.start.text_anchor..selection.end.text_anchor)
23108                        .to_point(buffer.read(cx)),
23109                )
23110            })
23111            .into_group_map();
23112
23113        cx.spawn_in(window, async move |_, cx| {
23114            workspace.update_in(cx, |workspace, window, cx| {
23115                Self::open_locations_in_multibuffer(
23116                    workspace,
23117                    locations,
23118                    format!("Selections for '{title}'"),
23119                    false,
23120                    false,
23121                    MultibufferSelectionMode::All,
23122                    window,
23123                    cx,
23124                );
23125            })
23126        })
23127        .detach();
23128    }
23129
23130    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23131    /// last highlight added will be used.
23132    ///
23133    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23134    pub fn highlight_rows<T: 'static>(
23135        &mut self,
23136        range: Range<Anchor>,
23137        color: Hsla,
23138        options: RowHighlightOptions,
23139        cx: &mut Context<Self>,
23140    ) {
23141        let snapshot = self.buffer().read(cx).snapshot(cx);
23142        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23143        let ix = row_highlights.binary_search_by(|highlight| {
23144            Ordering::Equal
23145                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23146                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23147        });
23148
23149        if let Err(mut ix) = ix {
23150            let index = post_inc(&mut self.highlight_order);
23151
23152            // If this range intersects with the preceding highlight, then merge it with
23153            // the preceding highlight. Otherwise insert a new highlight.
23154            let mut merged = false;
23155            if ix > 0 {
23156                let prev_highlight = &mut row_highlights[ix - 1];
23157                if prev_highlight
23158                    .range
23159                    .end
23160                    .cmp(&range.start, &snapshot)
23161                    .is_ge()
23162                {
23163                    ix -= 1;
23164                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23165                        prev_highlight.range.end = range.end;
23166                    }
23167                    merged = true;
23168                    prev_highlight.index = index;
23169                    prev_highlight.color = color;
23170                    prev_highlight.options = options;
23171                }
23172            }
23173
23174            if !merged {
23175                row_highlights.insert(
23176                    ix,
23177                    RowHighlight {
23178                        range,
23179                        index,
23180                        color,
23181                        options,
23182                        type_id: TypeId::of::<T>(),
23183                    },
23184                );
23185            }
23186
23187            // If any of the following highlights intersect with this one, merge them.
23188            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23189                let highlight = &row_highlights[ix];
23190                if next_highlight
23191                    .range
23192                    .start
23193                    .cmp(&highlight.range.end, &snapshot)
23194                    .is_le()
23195                {
23196                    if next_highlight
23197                        .range
23198                        .end
23199                        .cmp(&highlight.range.end, &snapshot)
23200                        .is_gt()
23201                    {
23202                        row_highlights[ix].range.end = next_highlight.range.end;
23203                    }
23204                    row_highlights.remove(ix + 1);
23205                } else {
23206                    break;
23207                }
23208            }
23209        }
23210    }
23211
23212    /// Remove any highlighted row ranges of the given type that intersect the
23213    /// given ranges.
23214    pub fn remove_highlighted_rows<T: 'static>(
23215        &mut self,
23216        ranges_to_remove: Vec<Range<Anchor>>,
23217        cx: &mut Context<Self>,
23218    ) {
23219        let snapshot = self.buffer().read(cx).snapshot(cx);
23220        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23221        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23222        row_highlights.retain(|highlight| {
23223            while let Some(range_to_remove) = ranges_to_remove.peek() {
23224                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23225                    Ordering::Less | Ordering::Equal => {
23226                        ranges_to_remove.next();
23227                    }
23228                    Ordering::Greater => {
23229                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23230                            Ordering::Less | Ordering::Equal => {
23231                                return false;
23232                            }
23233                            Ordering::Greater => break,
23234                        }
23235                    }
23236                }
23237            }
23238
23239            true
23240        })
23241    }
23242
23243    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23244    pub fn clear_row_highlights<T: 'static>(&mut self) {
23245        self.highlighted_rows.remove(&TypeId::of::<T>());
23246    }
23247
23248    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23249    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23250        self.highlighted_rows
23251            .get(&TypeId::of::<T>())
23252            .map_or(&[] as &[_], |vec| vec.as_slice())
23253            .iter()
23254            .map(|highlight| (highlight.range.clone(), highlight.color))
23255    }
23256
23257    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23258    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23259    /// Allows to ignore certain kinds of highlights.
23260    pub fn highlighted_display_rows(
23261        &self,
23262        window: &mut Window,
23263        cx: &mut App,
23264    ) -> BTreeMap<DisplayRow, LineHighlight> {
23265        let snapshot = self.snapshot(window, cx);
23266        let mut used_highlight_orders = HashMap::default();
23267        self.highlighted_rows
23268            .iter()
23269            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23270            .fold(
23271                BTreeMap::<DisplayRow, LineHighlight>::new(),
23272                |mut unique_rows, highlight| {
23273                    let start = highlight.range.start.to_display_point(&snapshot);
23274                    let end = highlight.range.end.to_display_point(&snapshot);
23275                    let start_row = start.row().0;
23276                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
23277                    {
23278                        end.row().0.saturating_sub(1)
23279                    } else {
23280                        end.row().0
23281                    };
23282                    for row in start_row..=end_row {
23283                        let used_index =
23284                            used_highlight_orders.entry(row).or_insert(highlight.index);
23285                        if highlight.index >= *used_index {
23286                            *used_index = highlight.index;
23287                            unique_rows.insert(
23288                                DisplayRow(row),
23289                                LineHighlight {
23290                                    include_gutter: highlight.options.include_gutter,
23291                                    border: None,
23292                                    background: highlight.color.into(),
23293                                    type_id: Some(highlight.type_id),
23294                                },
23295                            );
23296                        }
23297                    }
23298                    unique_rows
23299                },
23300            )
23301    }
23302
23303    pub fn highlighted_display_row_for_autoscroll(
23304        &self,
23305        snapshot: &DisplaySnapshot,
23306    ) -> Option<DisplayRow> {
23307        self.highlighted_rows
23308            .values()
23309            .flat_map(|highlighted_rows| highlighted_rows.iter())
23310            .filter_map(|highlight| {
23311                if highlight.options.autoscroll {
23312                    Some(highlight.range.start.to_display_point(snapshot).row())
23313                } else {
23314                    None
23315                }
23316            })
23317            .min()
23318    }
23319
23320    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23321        self.highlight_background(
23322            HighlightKey::SearchWithinRange,
23323            ranges,
23324            |_, colors| colors.colors().editor_document_highlight_read_background,
23325            cx,
23326        )
23327    }
23328
23329    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23330        self.breadcrumb_header = Some(new_header);
23331    }
23332
23333    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23334        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23335    }
23336
23337    pub fn highlight_background(
23338        &mut self,
23339        key: HighlightKey,
23340        ranges: &[Range<Anchor>],
23341        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23342        cx: &mut Context<Self>,
23343    ) {
23344        self.background_highlights
23345            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23346        self.scrollbar_marker_state.dirty = true;
23347        cx.notify();
23348    }
23349
23350    pub fn highlight_background_key(
23351        &mut self,
23352        key: HighlightKey,
23353        ranges: &[Range<Anchor>],
23354        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23355        cx: &mut Context<Self>,
23356    ) {
23357        self.background_highlights
23358            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23359        self.scrollbar_marker_state.dirty = true;
23360        cx.notify();
23361    }
23362
23363    pub fn clear_background_highlights(
23364        &mut self,
23365        key: HighlightKey,
23366        cx: &mut Context<Self>,
23367    ) -> Option<BackgroundHighlight> {
23368        let text_highlights = self.background_highlights.remove(&key)?;
23369        if !text_highlights.1.is_empty() {
23370            self.scrollbar_marker_state.dirty = true;
23371            cx.notify();
23372        }
23373        Some(text_highlights)
23374    }
23375
23376    pub fn highlight_gutter<T: 'static>(
23377        &mut self,
23378        ranges: impl Into<Vec<Range<Anchor>>>,
23379        color_fetcher: fn(&App) -> Hsla,
23380        cx: &mut Context<Self>,
23381    ) {
23382        self.gutter_highlights
23383            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23384        cx.notify();
23385    }
23386
23387    pub fn clear_gutter_highlights<T: 'static>(
23388        &mut self,
23389        cx: &mut Context<Self>,
23390    ) -> Option<GutterHighlight> {
23391        cx.notify();
23392        self.gutter_highlights.remove(&TypeId::of::<T>())
23393    }
23394
23395    pub fn insert_gutter_highlight<T: 'static>(
23396        &mut self,
23397        range: Range<Anchor>,
23398        color_fetcher: fn(&App) -> Hsla,
23399        cx: &mut Context<Self>,
23400    ) {
23401        let snapshot = self.buffer().read(cx).snapshot(cx);
23402        let mut highlights = self
23403            .gutter_highlights
23404            .remove(&TypeId::of::<T>())
23405            .map(|(_, highlights)| highlights)
23406            .unwrap_or_default();
23407        let ix = highlights.binary_search_by(|highlight| {
23408            Ordering::Equal
23409                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23410                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23411        });
23412        if let Err(ix) = ix {
23413            highlights.insert(ix, range);
23414        }
23415        self.gutter_highlights
23416            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23417    }
23418
23419    pub fn remove_gutter_highlights<T: 'static>(
23420        &mut self,
23421        ranges_to_remove: Vec<Range<Anchor>>,
23422        cx: &mut Context<Self>,
23423    ) {
23424        let snapshot = self.buffer().read(cx).snapshot(cx);
23425        let Some((color_fetcher, mut gutter_highlights)) =
23426            self.gutter_highlights.remove(&TypeId::of::<T>())
23427        else {
23428            return;
23429        };
23430        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23431        gutter_highlights.retain(|highlight| {
23432            while let Some(range_to_remove) = ranges_to_remove.peek() {
23433                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23434                    Ordering::Less | Ordering::Equal => {
23435                        ranges_to_remove.next();
23436                    }
23437                    Ordering::Greater => {
23438                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23439                            Ordering::Less | Ordering::Equal => {
23440                                return false;
23441                            }
23442                            Ordering::Greater => break,
23443                        }
23444                    }
23445                }
23446            }
23447
23448            true
23449        });
23450        self.gutter_highlights
23451            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23452    }
23453
23454    #[cfg(feature = "test-support")]
23455    pub fn all_text_highlights(
23456        &self,
23457        window: &mut Window,
23458        cx: &mut Context<Self>,
23459    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23460        let snapshot = self.snapshot(window, cx);
23461        self.display_map.update(cx, |display_map, _| {
23462            display_map
23463                .all_text_highlights()
23464                .map(|(_, highlight)| {
23465                    let (style, ranges) = highlight.as_ref();
23466                    (
23467                        *style,
23468                        ranges
23469                            .iter()
23470                            .map(|range| range.clone().to_display_points(&snapshot))
23471                            .collect(),
23472                    )
23473                })
23474                .collect()
23475        })
23476    }
23477
23478    #[cfg(feature = "test-support")]
23479    pub fn all_text_background_highlights(
23480        &self,
23481        window: &mut Window,
23482        cx: &mut Context<Self>,
23483    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23484        let snapshot = self.snapshot(window, cx);
23485        let buffer = &snapshot.buffer_snapshot();
23486        let start = buffer.anchor_before(MultiBufferOffset(0));
23487        let end = buffer.anchor_after(buffer.len());
23488        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23489    }
23490
23491    #[cfg(any(test, feature = "test-support"))]
23492    pub fn sorted_background_highlights_in_range(
23493        &self,
23494        search_range: Range<Anchor>,
23495        display_snapshot: &DisplaySnapshot,
23496        theme: &Theme,
23497    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23498        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23499        res.sort_by(|a, b| {
23500            a.0.start
23501                .cmp(&b.0.start)
23502                .then_with(|| a.0.end.cmp(&b.0.end))
23503                .then_with(|| a.1.cmp(&b.1))
23504        });
23505        res
23506    }
23507
23508    #[cfg(feature = "test-support")]
23509    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23510        let snapshot = self.buffer().read(cx).snapshot(cx);
23511
23512        let highlights = self
23513            .background_highlights
23514            .get(&HighlightKey::BufferSearchHighlights);
23515
23516        if let Some((_color, ranges)) = highlights {
23517            ranges
23518                .iter()
23519                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23520                .collect_vec()
23521        } else {
23522            vec![]
23523        }
23524    }
23525
23526    fn document_highlights_for_position<'a>(
23527        &'a self,
23528        position: Anchor,
23529        buffer: &'a MultiBufferSnapshot,
23530    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
23531        let read_highlights = self
23532            .background_highlights
23533            .get(&HighlightKey::DocumentHighlightRead)
23534            .map(|h| &h.1);
23535        let write_highlights = self
23536            .background_highlights
23537            .get(&HighlightKey::DocumentHighlightWrite)
23538            .map(|h| &h.1);
23539        let left_position = position.bias_left(buffer);
23540        let right_position = position.bias_right(buffer);
23541        read_highlights
23542            .into_iter()
23543            .chain(write_highlights)
23544            .flat_map(move |ranges| {
23545                let start_ix = match ranges.binary_search_by(|probe| {
23546                    let cmp = probe.end.cmp(&left_position, buffer);
23547                    if cmp.is_ge() {
23548                        Ordering::Greater
23549                    } else {
23550                        Ordering::Less
23551                    }
23552                }) {
23553                    Ok(i) | Err(i) => i,
23554                };
23555
23556                ranges[start_ix..]
23557                    .iter()
23558                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
23559            })
23560    }
23561
23562    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
23563        self.background_highlights
23564            .get(&key)
23565            .is_some_and(|(_, highlights)| !highlights.is_empty())
23566    }
23567
23568    /// Returns all background highlights for a given range.
23569    ///
23570    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23571    pub fn background_highlights_in_range(
23572        &self,
23573        search_range: Range<Anchor>,
23574        display_snapshot: &DisplaySnapshot,
23575        theme: &Theme,
23576    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23577        let mut results = Vec::new();
23578        for (color_fetcher, ranges) in self.background_highlights.values() {
23579            let start_ix = match ranges.binary_search_by(|probe| {
23580                let cmp = probe
23581                    .end
23582                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23583                if cmp.is_gt() {
23584                    Ordering::Greater
23585                } else {
23586                    Ordering::Less
23587                }
23588            }) {
23589                Ok(i) | Err(i) => i,
23590            };
23591            for (index, range) in ranges[start_ix..].iter().enumerate() {
23592                if range
23593                    .start
23594                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23595                    .is_ge()
23596                {
23597                    break;
23598                }
23599
23600                let color = color_fetcher(&(start_ix + index), theme);
23601                let start = range.start.to_display_point(display_snapshot);
23602                let end = range.end.to_display_point(display_snapshot);
23603                results.push((start..end, color))
23604            }
23605        }
23606        results
23607    }
23608
23609    pub fn gutter_highlights_in_range(
23610        &self,
23611        search_range: Range<Anchor>,
23612        display_snapshot: &DisplaySnapshot,
23613        cx: &App,
23614    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23615        let mut results = Vec::new();
23616        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23617            let color = color_fetcher(cx);
23618            let start_ix = match ranges.binary_search_by(|probe| {
23619                let cmp = probe
23620                    .end
23621                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23622                if cmp.is_gt() {
23623                    Ordering::Greater
23624                } else {
23625                    Ordering::Less
23626                }
23627            }) {
23628                Ok(i) | Err(i) => i,
23629            };
23630            for range in &ranges[start_ix..] {
23631                if range
23632                    .start
23633                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23634                    .is_ge()
23635                {
23636                    break;
23637                }
23638
23639                let start = range.start.to_display_point(display_snapshot);
23640                let end = range.end.to_display_point(display_snapshot);
23641                results.push((start..end, color))
23642            }
23643        }
23644        results
23645    }
23646
23647    /// Get the text ranges corresponding to the redaction query
23648    pub fn redacted_ranges(
23649        &self,
23650        search_range: Range<Anchor>,
23651        display_snapshot: &DisplaySnapshot,
23652        cx: &App,
23653    ) -> Vec<Range<DisplayPoint>> {
23654        display_snapshot
23655            .buffer_snapshot()
23656            .redacted_ranges(search_range, |file| {
23657                if let Some(file) = file {
23658                    file.is_private()
23659                        && EditorSettings::get(
23660                            Some(SettingsLocation {
23661                                worktree_id: file.worktree_id(cx),
23662                                path: file.path().as_ref(),
23663                            }),
23664                            cx,
23665                        )
23666                        .redact_private_values
23667                } else {
23668                    false
23669                }
23670            })
23671            .map(|range| {
23672                range.start.to_display_point(display_snapshot)
23673                    ..range.end.to_display_point(display_snapshot)
23674            })
23675            .collect()
23676    }
23677
23678    pub fn highlight_text_key(
23679        &mut self,
23680        key: HighlightKey,
23681        ranges: Vec<Range<Anchor>>,
23682        style: HighlightStyle,
23683        merge: bool,
23684        cx: &mut Context<Self>,
23685    ) {
23686        self.display_map.update(cx, |map, cx| {
23687            map.highlight_text(key, ranges, style, merge, cx);
23688        });
23689        cx.notify();
23690    }
23691
23692    pub fn highlight_text(
23693        &mut self,
23694        key: HighlightKey,
23695        ranges: Vec<Range<Anchor>>,
23696        style: HighlightStyle,
23697        cx: &mut Context<Self>,
23698    ) {
23699        self.display_map.update(cx, |map, cx| {
23700            map.highlight_text(key, ranges, style, false, cx)
23701        });
23702        cx.notify();
23703    }
23704
23705    pub fn text_highlights<'a>(
23706        &'a self,
23707        key: HighlightKey,
23708        cx: &'a App,
23709    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
23710        self.display_map.read(cx).text_highlights(key)
23711    }
23712
23713    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
23714        let cleared = self
23715            .display_map
23716            .update(cx, |map, _| map.clear_highlights(key));
23717        if cleared {
23718            cx.notify();
23719        }
23720    }
23721
23722    pub fn clear_highlights_with(
23723        &mut self,
23724        f: impl FnMut(&HighlightKey) -> bool,
23725        cx: &mut Context<Self>,
23726    ) {
23727        let cleared = self
23728            .display_map
23729            .update(cx, |map, _| map.clear_highlights_with(f));
23730        if cleared {
23731            cx.notify();
23732        }
23733    }
23734
23735    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
23736        (self.read_only(cx) || self.blink_manager.read(cx).visible())
23737            && self.focus_handle.is_focused(window)
23738    }
23739
23740    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
23741        self.show_cursor_when_unfocused = is_enabled;
23742        cx.notify();
23743    }
23744
23745    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
23746        cx.notify();
23747    }
23748
23749    fn on_debug_session_event(
23750        &mut self,
23751        _session: Entity<Session>,
23752        event: &SessionEvent,
23753        cx: &mut Context<Self>,
23754    ) {
23755        if let SessionEvent::InvalidateInlineValue = event {
23756            self.refresh_inline_values(cx);
23757        }
23758    }
23759
23760    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
23761        let Some(project) = self.project.clone() else {
23762            return;
23763        };
23764
23765        if !self.inline_value_cache.enabled {
23766            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
23767            self.splice_inlays(&inlays, Vec::new(), cx);
23768            return;
23769        }
23770
23771        let current_execution_position = self
23772            .highlighted_rows
23773            .get(&TypeId::of::<ActiveDebugLine>())
23774            .and_then(|lines| lines.last().map(|line| line.range.end));
23775
23776        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
23777            let inline_values = editor
23778                .update(cx, |editor, cx| {
23779                    let Some(current_execution_position) = current_execution_position else {
23780                        return Some(Task::ready(Ok(Vec::new())));
23781                    };
23782
23783                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
23784                        let snapshot = buffer.snapshot(cx);
23785
23786                        let excerpt = snapshot.excerpt_containing(
23787                            current_execution_position..current_execution_position,
23788                        )?;
23789
23790                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
23791                    })?;
23792
23793                    let range =
23794                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
23795
23796                    project.inline_values(buffer, range, cx)
23797                })
23798                .ok()
23799                .flatten()?
23800                .await
23801                .context("refreshing debugger inlays")
23802                .log_err()?;
23803
23804            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
23805
23806            for (buffer_id, inline_value) in inline_values
23807                .into_iter()
23808                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
23809            {
23810                buffer_inline_values
23811                    .entry(buffer_id)
23812                    .or_default()
23813                    .push(inline_value);
23814            }
23815
23816            editor
23817                .update(cx, |editor, cx| {
23818                    let snapshot = editor.buffer.read(cx).snapshot(cx);
23819                    let mut new_inlays = Vec::default();
23820
23821                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
23822                        let buffer_id = buffer_snapshot.remote_id();
23823                        buffer_inline_values
23824                            .get(&buffer_id)
23825                            .into_iter()
23826                            .flatten()
23827                            .for_each(|hint| {
23828                                let inlay = Inlay::debugger(
23829                                    post_inc(&mut editor.next_inlay_id),
23830                                    Anchor::in_buffer(excerpt_id, hint.position),
23831                                    hint.text(),
23832                                );
23833                                if !inlay.text().chars().contains(&'\n') {
23834                                    new_inlays.push(inlay);
23835                                }
23836                            });
23837                    }
23838
23839                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
23840                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
23841
23842                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
23843                })
23844                .ok()?;
23845            Some(())
23846        });
23847    }
23848
23849    fn on_buffer_event(
23850        &mut self,
23851        multibuffer: &Entity<MultiBuffer>,
23852        event: &multi_buffer::Event,
23853        window: &mut Window,
23854        cx: &mut Context<Self>,
23855    ) {
23856        match event {
23857            multi_buffer::Event::Edited { edited_buffer } => {
23858                self.scrollbar_marker_state.dirty = true;
23859                self.active_indent_guides_state.dirty = true;
23860                self.refresh_active_diagnostics(cx);
23861                self.refresh_code_actions(window, cx);
23862                self.refresh_single_line_folds(window, cx);
23863                self.refresh_matching_bracket_highlights(window, cx);
23864                self.refresh_outline_symbols(cx);
23865                self.refresh_sticky_headers(&self.snapshot(window, cx), cx);
23866                if self.has_active_edit_prediction() {
23867                    self.update_visible_edit_prediction(window, cx);
23868                }
23869
23870                // Clean up orphaned review comments after edits
23871                self.cleanup_orphaned_review_comments(cx);
23872
23873                if let Some(buffer) = edited_buffer {
23874                    if buffer.read(cx).file().is_none() {
23875                        cx.emit(EditorEvent::TitleChanged);
23876                    }
23877
23878                    if self.project.is_some() {
23879                        let buffer_id = buffer.read(cx).remote_id();
23880                        self.register_buffer(buffer_id, cx);
23881                        self.update_lsp_data(Some(buffer_id), window, cx);
23882                        self.refresh_inlay_hints(
23883                            InlayHintRefreshReason::BufferEdited(buffer_id),
23884                            cx,
23885                        );
23886                    }
23887                }
23888
23889                cx.emit(EditorEvent::BufferEdited);
23890                cx.emit(SearchEvent::MatchesInvalidated);
23891
23892                let Some(project) = &self.project else { return };
23893                let (telemetry, is_via_ssh) = {
23894                    let project = project.read(cx);
23895                    let telemetry = project.client().telemetry().clone();
23896                    let is_via_ssh = project.is_via_remote_server();
23897                    (telemetry, is_via_ssh)
23898                };
23899                telemetry.log_edit_event("editor", is_via_ssh);
23900            }
23901            multi_buffer::Event::ExcerptsAdded {
23902                buffer,
23903                predecessor,
23904                excerpts,
23905            } => {
23906                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23907                let buffer_id = buffer.read(cx).remote_id();
23908                if self.buffer.read(cx).diff_for(buffer_id).is_none()
23909                    && let Some(project) = &self.project
23910                {
23911                    update_uncommitted_diff_for_buffer(
23912                        cx.entity(),
23913                        project,
23914                        [buffer.clone()],
23915                        self.buffer.clone(),
23916                        cx,
23917                    )
23918                    .detach();
23919                }
23920                self.semantic_token_state
23921                    .invalidate_buffer(&buffer.read(cx).remote_id());
23922                self.update_lsp_data(Some(buffer_id), window, cx);
23923                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23924                self.colorize_brackets(false, cx);
23925                self.refresh_selected_text_highlights(true, window, cx);
23926                cx.emit(EditorEvent::ExcerptsAdded {
23927                    buffer: buffer.clone(),
23928                    predecessor: *predecessor,
23929                    excerpts: excerpts.clone(),
23930                });
23931            }
23932            multi_buffer::Event::ExcerptsRemoved {
23933                ids,
23934                removed_buffer_ids,
23935            } => {
23936                if let Some(inlay_hints) = &mut self.inlay_hints {
23937                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
23938                }
23939                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
23940                for buffer_id in removed_buffer_ids {
23941                    self.registered_buffers.remove(buffer_id);
23942                    self.tasks
23943                        .retain(|(task_buffer_id, _), _| task_buffer_id != buffer_id);
23944                    self.semantic_token_state.invalidate_buffer(buffer_id);
23945                    self.display_map.update(cx, |display_map, cx| {
23946                        display_map.invalidate_semantic_highlights(*buffer_id);
23947                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
23948                    });
23949                }
23950                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23951                cx.emit(EditorEvent::ExcerptsRemoved {
23952                    ids: ids.clone(),
23953                    removed_buffer_ids: removed_buffer_ids.clone(),
23954                });
23955            }
23956            multi_buffer::Event::ExcerptsEdited {
23957                excerpt_ids,
23958                buffer_ids,
23959            } => {
23960                self.display_map.update(cx, |map, cx| {
23961                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
23962                });
23963                cx.emit(EditorEvent::ExcerptsEdited {
23964                    ids: excerpt_ids.clone(),
23965                });
23966            }
23967            multi_buffer::Event::ExcerptsExpanded { ids } => {
23968                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23969                self.refresh_document_highlights(cx);
23970                let snapshot = multibuffer.read(cx).snapshot(cx);
23971                for id in ids {
23972                    self.fetched_tree_sitter_chunks.remove(id);
23973                    if let Some(buffer) = snapshot.buffer_for_excerpt(*id) {
23974                        self.semantic_token_state
23975                            .invalidate_buffer(&buffer.remote_id());
23976                    }
23977                }
23978                self.colorize_brackets(false, cx);
23979                self.update_lsp_data(None, window, cx);
23980                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
23981            }
23982            multi_buffer::Event::Reparsed(buffer_id) => {
23983                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23984                self.refresh_selected_text_highlights(true, window, cx);
23985                self.colorize_brackets(true, cx);
23986                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23987
23988                cx.emit(EditorEvent::Reparsed(*buffer_id));
23989            }
23990            multi_buffer::Event::DiffHunksToggled => {
23991                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23992            }
23993            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
23994                if !is_fresh_language {
23995                    self.registered_buffers.remove(&buffer_id);
23996                }
23997                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23998                cx.emit(EditorEvent::Reparsed(*buffer_id));
23999                cx.notify();
24000            }
24001            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24002            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24003            multi_buffer::Event::FileHandleChanged
24004            | multi_buffer::Event::Reloaded
24005            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24006            multi_buffer::Event::DiagnosticsUpdated => {
24007                self.update_diagnostics_state(window, cx);
24008            }
24009            _ => {}
24010        };
24011    }
24012
24013    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24014        if !self.diagnostics_enabled() {
24015            return;
24016        }
24017        self.refresh_active_diagnostics(cx);
24018        self.refresh_inline_diagnostics(true, window, cx);
24019        self.scrollbar_marker_state.dirty = true;
24020        cx.notify();
24021    }
24022
24023    pub fn start_temporary_diff_override(&mut self) {
24024        self.load_diff_task.take();
24025        self.temporary_diff_override = true;
24026    }
24027
24028    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24029        self.temporary_diff_override = false;
24030        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24031        self.buffer.update(cx, |buffer, cx| {
24032            buffer.set_all_diff_hunks_collapsed(cx);
24033        });
24034
24035        if let Some(project) = self.project.clone() {
24036            self.load_diff_task = Some(
24037                update_uncommitted_diff_for_buffer(
24038                    cx.entity(),
24039                    &project,
24040                    self.buffer.read(cx).all_buffers(),
24041                    self.buffer.clone(),
24042                    cx,
24043                )
24044                .shared(),
24045            );
24046        }
24047    }
24048
24049    fn on_display_map_changed(
24050        &mut self,
24051        _: Entity<DisplayMap>,
24052        _: &mut Window,
24053        cx: &mut Context<Self>,
24054    ) {
24055        cx.notify();
24056    }
24057
24058    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24059        if !self.mode.is_full() {
24060            return None;
24061        }
24062
24063        let theme_settings = theme::ThemeSettings::get_global(cx);
24064        let theme = cx.theme();
24065        let accent_colors = theme.accents().clone();
24066
24067        let accent_overrides = theme_settings
24068            .theme_overrides
24069            .get(theme.name.as_ref())
24070            .map(|theme_style| &theme_style.accents)
24071            .into_iter()
24072            .flatten()
24073            .chain(
24074                theme_settings
24075                    .experimental_theme_overrides
24076                    .as_ref()
24077                    .map(|overrides| &overrides.accents)
24078                    .into_iter()
24079                    .flatten(),
24080            )
24081            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24082            .collect();
24083
24084        Some(AccentData {
24085            colors: accent_colors,
24086            overrides: accent_overrides,
24087        })
24088    }
24089
24090    fn fetch_applicable_language_settings(
24091        &self,
24092        cx: &App,
24093    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24094        if !self.mode.is_full() {
24095            return HashMap::default();
24096        }
24097
24098        self.buffer().read(cx).all_buffers().into_iter().fold(
24099            HashMap::default(),
24100            |mut acc, buffer| {
24101                let buffer = buffer.read(cx);
24102                let language = buffer.language().map(|language| language.name());
24103                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
24104                    let file = buffer.file();
24105                    v.insert(language_settings(language, file, cx).into_owned());
24106                }
24107                acc
24108            },
24109        )
24110    }
24111
24112    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24113        let new_language_settings = self.fetch_applicable_language_settings(cx);
24114        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24115        self.applicable_language_settings = new_language_settings;
24116
24117        let new_accents = self.fetch_accent_data(cx);
24118        let accents_changed = new_accents != self.accent_data;
24119        self.accent_data = new_accents;
24120
24121        if self.diagnostics_enabled() {
24122            let new_severity = EditorSettings::get_global(cx)
24123                .diagnostics_max_severity
24124                .unwrap_or(DiagnosticSeverity::Hint);
24125            self.set_max_diagnostics_severity(new_severity, cx);
24126        }
24127        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
24128        self.update_edit_prediction_settings(cx);
24129        self.refresh_edit_prediction(true, false, window, cx);
24130        self.refresh_inline_values(cx);
24131
24132        let old_cursor_shape = self.cursor_shape;
24133        let old_show_breadcrumbs = self.show_breadcrumbs;
24134
24135        {
24136            let editor_settings = EditorSettings::get_global(cx);
24137            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24138            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24139            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24140            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24141        }
24142
24143        if old_cursor_shape != self.cursor_shape {
24144            cx.emit(EditorEvent::CursorShapeChanged);
24145        }
24146
24147        if old_show_breadcrumbs != self.show_breadcrumbs {
24148            cx.emit(EditorEvent::BreadcrumbsChanged);
24149        }
24150
24151        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24152            let project_settings = ProjectSettings::get_global(cx);
24153            (
24154                project_settings.session.restore_unsaved_buffers,
24155                project_settings.diagnostics.inline.enabled,
24156                project_settings.git.inline_blame.enabled,
24157            )
24158        };
24159        self.buffer_serialization = self
24160            .should_serialize_buffer()
24161            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24162
24163        if self.mode.is_full() {
24164            if self.show_inline_diagnostics != show_inline_diagnostics {
24165                self.show_inline_diagnostics = show_inline_diagnostics;
24166                self.refresh_inline_diagnostics(false, window, cx);
24167            }
24168
24169            if self.git_blame_inline_enabled != inline_blame_enabled {
24170                self.toggle_git_blame_inline_internal(false, window, cx);
24171            }
24172
24173            let minimap_settings = EditorSettings::get_global(cx).minimap;
24174            if self.minimap_visibility != MinimapVisibility::Disabled {
24175                if self.minimap_visibility.settings_visibility()
24176                    != minimap_settings.minimap_enabled()
24177                {
24178                    self.set_minimap_visibility(
24179                        MinimapVisibility::for_mode(self.mode(), cx),
24180                        window,
24181                        cx,
24182                    );
24183                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24184                    minimap_entity.update(cx, |minimap_editor, cx| {
24185                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24186                    })
24187                }
24188            }
24189
24190            if language_settings_changed || accents_changed {
24191                self.colorize_brackets(true, cx);
24192            }
24193
24194            if language_settings_changed {
24195                self.clear_disabled_lsp_folding_ranges(window, cx);
24196            }
24197
24198            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24199                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24200            }) {
24201                if !inlay_splice.is_empty() {
24202                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24203                }
24204                self.refresh_colors_for_visible_range(None, window, cx);
24205            }
24206
24207            self.refresh_inlay_hints(
24208                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24209                    self.selections.newest_anchor().head(),
24210                    &self.buffer.read(cx).snapshot(cx),
24211                    cx,
24212                )),
24213                cx,
24214            );
24215
24216            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24217                .global_lsp_settings
24218                .semantic_token_rules
24219                .clone();
24220            let semantic_token_rules_changed = self
24221                .semantic_token_state
24222                .update_rules(new_semantic_token_rules);
24223            if language_settings_changed || semantic_token_rules_changed {
24224                self.refresh_semantic_token_highlights(cx);
24225            }
24226        }
24227
24228        cx.notify();
24229    }
24230
24231    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24232        if !self.mode.is_full() {
24233            return;
24234        }
24235
24236        let new_accents = self.fetch_accent_data(cx);
24237        if new_accents != self.accent_data {
24238            self.accent_data = new_accents;
24239            self.colorize_brackets(true, cx);
24240        }
24241
24242        self.refresh_semantic_token_highlights(cx);
24243    }
24244
24245    pub fn set_searchable(&mut self, searchable: bool) {
24246        self.searchable = searchable;
24247    }
24248
24249    pub fn searchable(&self) -> bool {
24250        self.searchable
24251    }
24252
24253    pub fn open_excerpts_in_split(
24254        &mut self,
24255        _: &OpenExcerptsSplit,
24256        window: &mut Window,
24257        cx: &mut Context<Self>,
24258    ) {
24259        self.open_excerpts_common(None, true, window, cx)
24260    }
24261
24262    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24263        self.open_excerpts_common(None, false, window, cx)
24264    }
24265
24266    pub(crate) fn open_excerpts_common(
24267        &mut self,
24268        jump_data: Option<JumpData>,
24269        split: bool,
24270        window: &mut Window,
24271        cx: &mut Context<Self>,
24272    ) {
24273        if self.buffer.read(cx).is_singleton() {
24274            cx.propagate();
24275            return;
24276        }
24277
24278        let mut new_selections_by_buffer = HashMap::default();
24279        match &jump_data {
24280            Some(JumpData::MultiBufferPoint {
24281                excerpt_id,
24282                position,
24283                anchor,
24284                line_offset_from_top,
24285            }) => {
24286                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
24287                if let Some(buffer) = multi_buffer_snapshot
24288                    .buffer_id_for_excerpt(*excerpt_id)
24289                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
24290                {
24291                    let buffer_snapshot = buffer.read(cx).snapshot();
24292                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
24293                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24294                    } else {
24295                        buffer_snapshot.clip_point(*position, Bias::Left)
24296                    };
24297                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24298                    new_selections_by_buffer.insert(
24299                        buffer,
24300                        (
24301                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24302                            Some(*line_offset_from_top),
24303                        ),
24304                    );
24305                }
24306            }
24307            Some(JumpData::MultiBufferRow {
24308                row,
24309                line_offset_from_top,
24310            }) => {
24311                let point = MultiBufferPoint::new(row.0, 0);
24312                if let Some((buffer, buffer_point, _)) =
24313                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24314                {
24315                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24316                    new_selections_by_buffer
24317                        .entry(buffer)
24318                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24319                        .0
24320                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24321                }
24322            }
24323            None => {
24324                let selections = self
24325                    .selections
24326                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24327                let multi_buffer = self.buffer.read(cx);
24328                for selection in selections {
24329                    for (snapshot, range, _, anchor) in multi_buffer
24330                        .snapshot(cx)
24331                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24332                    {
24333                        if let Some(anchor) = anchor {
24334                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
24335                            else {
24336                                continue;
24337                            };
24338                            let offset = text::ToOffset::to_offset(
24339                                &anchor.text_anchor,
24340                                &buffer_handle.read(cx).snapshot(),
24341                            );
24342                            let range = BufferOffset(offset)..BufferOffset(offset);
24343                            new_selections_by_buffer
24344                                .entry(buffer_handle)
24345                                .or_insert((Vec::new(), None))
24346                                .0
24347                                .push(range)
24348                        } else {
24349                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24350                            else {
24351                                continue;
24352                            };
24353                            new_selections_by_buffer
24354                                .entry(buffer_handle)
24355                                .or_insert((Vec::new(), None))
24356                                .0
24357                                .push(range)
24358                        }
24359                    }
24360                }
24361            }
24362        }
24363
24364        if self.delegate_open_excerpts {
24365            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24366                .into_iter()
24367                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24368                .collect();
24369            if !selections_by_buffer.is_empty() {
24370                cx.emit(EditorEvent::OpenExcerptsRequested {
24371                    selections_by_buffer,
24372                    split,
24373                });
24374            }
24375            return;
24376        }
24377
24378        let Some(workspace) = self.workspace() else {
24379            cx.propagate();
24380            return;
24381        };
24382
24383        new_selections_by_buffer
24384            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24385
24386        if new_selections_by_buffer.is_empty() {
24387            return;
24388        }
24389
24390        Self::open_buffers_in_workspace(
24391            workspace.downgrade(),
24392            new_selections_by_buffer,
24393            split,
24394            window,
24395            cx,
24396        );
24397    }
24398
24399    pub(crate) fn open_buffers_in_workspace(
24400        workspace: WeakEntity<Workspace>,
24401        new_selections_by_buffer: HashMap<
24402            Entity<language::Buffer>,
24403            (Vec<Range<BufferOffset>>, Option<u32>),
24404        >,
24405        split: bool,
24406        window: &mut Window,
24407        cx: &mut App,
24408    ) {
24409        // We defer the pane interaction because we ourselves are a workspace item
24410        // and activating a new item causes the pane to call a method on us reentrantly,
24411        // which panics if we're on the stack.
24412        window.defer(cx, move |window, cx| {
24413            workspace
24414                .update(cx, |workspace, cx| {
24415                    let pane = if split {
24416                        workspace.adjacent_pane(window, cx)
24417                    } else {
24418                        workspace.active_pane().clone()
24419                    };
24420
24421                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24422                        let buffer_read = buffer.read(cx);
24423                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24424                            (true, project::File::from_dyn(Some(file)).is_some())
24425                        } else {
24426                            (false, false)
24427                        };
24428
24429                        // If project file is none workspace.open_project_item will fail to open the excerpt
24430                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24431                        // so we check if there's a tab match in that case first
24432                        let editor = (!has_file || !is_project_file)
24433                            .then(|| {
24434                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24435                                // so `workspace.open_project_item` will never find them, always opening a new editor.
24436                                // Instead, we try to activate the existing editor in the pane first.
24437                                let (editor, pane_item_index, pane_item_id) =
24438                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
24439                                        let editor = item.downcast::<Editor>()?;
24440                                        let singleton_buffer =
24441                                            editor.read(cx).buffer().read(cx).as_singleton()?;
24442                                        if singleton_buffer == buffer {
24443                                            Some((editor, i, item.item_id()))
24444                                        } else {
24445                                            None
24446                                        }
24447                                    })?;
24448                                pane.update(cx, |pane, cx| {
24449                                    pane.activate_item(pane_item_index, true, true, window, cx);
24450                                    if !PreviewTabsSettings::get_global(cx)
24451                                        .enable_preview_from_multibuffer
24452                                    {
24453                                        pane.unpreview_item_if_preview(pane_item_id);
24454                                    }
24455                                });
24456                                Some(editor)
24457                            })
24458                            .flatten()
24459                            .unwrap_or_else(|| {
24460                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
24461                                    .enable_keep_preview_on_code_navigation;
24462                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
24463                                    .enable_preview_from_multibuffer;
24464                                workspace.open_project_item::<Self>(
24465                                    pane.clone(),
24466                                    buffer,
24467                                    true,
24468                                    true,
24469                                    keep_old_preview,
24470                                    allow_new_preview,
24471                                    window,
24472                                    cx,
24473                                )
24474                            });
24475
24476                        editor.update(cx, |editor, cx| {
24477                            if has_file && !is_project_file {
24478                                editor.set_read_only(true);
24479                            }
24480                            let autoscroll = match scroll_offset {
24481                                Some(scroll_offset) => {
24482                                    Autoscroll::top_relative(scroll_offset as usize)
24483                                }
24484                                None => Autoscroll::newest(),
24485                            };
24486                            let nav_history = editor.nav_history.take();
24487                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24488                            let Some((&excerpt_id, _, buffer_snapshot)) =
24489                                multibuffer_snapshot.as_singleton()
24490                            else {
24491                                return;
24492                            };
24493                            editor.change_selections(
24494                                SelectionEffects::scroll(autoscroll),
24495                                window,
24496                                cx,
24497                                |s| {
24498                                    s.select_ranges(ranges.into_iter().map(|range| {
24499                                        let range = buffer_snapshot.anchor_before(range.start)
24500                                            ..buffer_snapshot.anchor_after(range.end);
24501                                        multibuffer_snapshot
24502                                            .anchor_range_in_excerpt(excerpt_id, range)
24503                                            .unwrap()
24504                                    }));
24505                                },
24506                            );
24507                            editor.nav_history = nav_history;
24508                        });
24509                    }
24510                })
24511                .ok();
24512        });
24513    }
24514
24515    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24516        let snapshot = self.buffer.read(cx).read(cx);
24517        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
24518        Some(
24519            ranges
24520                .iter()
24521                .map(move |range| {
24522                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24523                })
24524                .collect(),
24525        )
24526    }
24527
24528    fn selection_replacement_ranges(
24529        &self,
24530        range: Range<MultiBufferOffsetUtf16>,
24531        cx: &mut App,
24532    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24533        let selections = self
24534            .selections
24535            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24536        let newest_selection = selections
24537            .iter()
24538            .max_by_key(|selection| selection.id)
24539            .unwrap();
24540        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24541        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24542        let snapshot = self.buffer.read(cx).read(cx);
24543        selections
24544            .into_iter()
24545            .map(|mut selection| {
24546                selection.start.0.0 =
24547                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24548                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24549                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24550                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24551            })
24552            .collect()
24553    }
24554
24555    fn report_editor_event(
24556        &self,
24557        reported_event: ReportEditorEvent,
24558        file_extension: Option<String>,
24559        cx: &App,
24560    ) {
24561        if cfg!(any(test, feature = "test-support")) {
24562            return;
24563        }
24564
24565        let Some(project) = &self.project else { return };
24566
24567        // If None, we are in a file without an extension
24568        let file = self
24569            .buffer
24570            .read(cx)
24571            .as_singleton()
24572            .and_then(|b| b.read(cx).file());
24573        let file_extension = file_extension.or(file
24574            .as_ref()
24575            .and_then(|file| Path::new(file.file_name(cx)).extension())
24576            .and_then(|e| e.to_str())
24577            .map(|a| a.to_string()));
24578
24579        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24580            .map(|vim_mode| vim_mode.0)
24581            .unwrap_or(false);
24582
24583        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24584        let copilot_enabled = edit_predictions_provider
24585            == language::language_settings::EditPredictionProvider::Copilot;
24586        let copilot_enabled_for_language = self
24587            .buffer
24588            .read(cx)
24589            .language_settings(cx)
24590            .show_edit_predictions;
24591
24592        let project = project.read(cx);
24593        let event_type = reported_event.event_type();
24594
24595        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24596            telemetry::event!(
24597                event_type,
24598                type = if auto_saved {"autosave"} else {"manual"},
24599                file_extension,
24600                vim_mode,
24601                copilot_enabled,
24602                copilot_enabled_for_language,
24603                edit_predictions_provider,
24604                is_via_ssh = project.is_via_remote_server(),
24605            );
24606        } else {
24607            telemetry::event!(
24608                event_type,
24609                file_extension,
24610                vim_mode,
24611                copilot_enabled,
24612                copilot_enabled_for_language,
24613                edit_predictions_provider,
24614                is_via_ssh = project.is_via_remote_server(),
24615            );
24616        };
24617    }
24618
24619    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24620    /// with each line being an array of {text, highlight} objects.
24621    fn copy_highlight_json(
24622        &mut self,
24623        _: &CopyHighlightJson,
24624        window: &mut Window,
24625        cx: &mut Context<Self>,
24626    ) {
24627        #[derive(Serialize)]
24628        struct Chunk<'a> {
24629            text: String,
24630            highlight: Option<&'a str>,
24631        }
24632
24633        let snapshot = self.buffer.read(cx).snapshot(cx);
24634        let range = self
24635            .selected_text_range(false, window, cx)
24636            .and_then(|selection| {
24637                if selection.range.is_empty() {
24638                    None
24639                } else {
24640                    Some(
24641                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24642                            selection.range.start,
24643                        )))
24644                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24645                                selection.range.end,
24646                            ))),
24647                    )
24648                }
24649            })
24650            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
24651
24652        let chunks = snapshot.chunks(range, true);
24653        let mut lines = Vec::new();
24654        let mut line: VecDeque<Chunk> = VecDeque::new();
24655
24656        let Some(style) = self.style.as_ref() else {
24657            return;
24658        };
24659
24660        for chunk in chunks {
24661            let highlight = chunk
24662                .syntax_highlight_id
24663                .and_then(|id| id.name(&style.syntax));
24664            let mut chunk_lines = chunk.text.split('\n').peekable();
24665            while let Some(text) = chunk_lines.next() {
24666                let mut merged_with_last_token = false;
24667                if let Some(last_token) = line.back_mut()
24668                    && last_token.highlight == highlight
24669                {
24670                    last_token.text.push_str(text);
24671                    merged_with_last_token = true;
24672                }
24673
24674                if !merged_with_last_token {
24675                    line.push_back(Chunk {
24676                        text: text.into(),
24677                        highlight,
24678                    });
24679                }
24680
24681                if chunk_lines.peek().is_some() {
24682                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
24683                        line.pop_front();
24684                    }
24685                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
24686                        line.pop_back();
24687                    }
24688
24689                    lines.push(mem::take(&mut line));
24690                }
24691            }
24692        }
24693
24694        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
24695            return;
24696        };
24697        cx.write_to_clipboard(ClipboardItem::new_string(lines));
24698    }
24699
24700    pub fn open_context_menu(
24701        &mut self,
24702        _: &OpenContextMenu,
24703        window: &mut Window,
24704        cx: &mut Context<Self>,
24705    ) {
24706        self.request_autoscroll(Autoscroll::newest(), cx);
24707        let position = self
24708            .selections
24709            .newest_display(&self.display_snapshot(cx))
24710            .start;
24711        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
24712    }
24713
24714    pub fn replay_insert_event(
24715        &mut self,
24716        text: &str,
24717        relative_utf16_range: Option<Range<isize>>,
24718        window: &mut Window,
24719        cx: &mut Context<Self>,
24720    ) {
24721        if !self.input_enabled {
24722            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24723            return;
24724        }
24725        if let Some(relative_utf16_range) = relative_utf16_range {
24726            let selections = self
24727                .selections
24728                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24729            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24730                let new_ranges = selections.into_iter().map(|range| {
24731                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
24732                        range
24733                            .head()
24734                            .0
24735                            .0
24736                            .saturating_add_signed(relative_utf16_range.start),
24737                    ));
24738                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
24739                        range
24740                            .head()
24741                            .0
24742                            .0
24743                            .saturating_add_signed(relative_utf16_range.end),
24744                    ));
24745                    start..end
24746                });
24747                s.select_ranges(new_ranges);
24748            });
24749        }
24750
24751        self.handle_input(text, window, cx);
24752    }
24753
24754    pub fn is_focused(&self, window: &Window) -> bool {
24755        self.focus_handle.is_focused(window)
24756    }
24757
24758    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24759        cx.emit(EditorEvent::Focused);
24760
24761        if let Some(descendant) = self
24762            .last_focused_descendant
24763            .take()
24764            .and_then(|descendant| descendant.upgrade())
24765        {
24766            window.focus(&descendant, cx);
24767        } else {
24768            if let Some(blame) = self.blame.as_ref() {
24769                blame.update(cx, GitBlame::focus)
24770            }
24771
24772            self.blink_manager.update(cx, BlinkManager::enable);
24773            self.show_cursor_names(window, cx);
24774            self.buffer.update(cx, |buffer, cx| {
24775                buffer.finalize_last_transaction(cx);
24776                if self.leader_id.is_none() {
24777                    buffer.set_active_selections(
24778                        &self.selections.disjoint_anchors_arc(),
24779                        self.selections.line_mode(),
24780                        self.cursor_shape,
24781                        cx,
24782                    );
24783                }
24784            });
24785
24786            if let Some(position_map) = self.last_position_map.clone() {
24787                EditorElement::mouse_moved(
24788                    self,
24789                    &MouseMoveEvent {
24790                        position: window.mouse_position(),
24791                        pressed_button: None,
24792                        modifiers: window.modifiers(),
24793                    },
24794                    &position_map,
24795                    None,
24796                    window,
24797                    cx,
24798                );
24799            }
24800        }
24801    }
24802
24803    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24804        cx.emit(EditorEvent::FocusedIn)
24805    }
24806
24807    fn handle_focus_out(
24808        &mut self,
24809        event: FocusOutEvent,
24810        _window: &mut Window,
24811        cx: &mut Context<Self>,
24812    ) {
24813        if event.blurred != self.focus_handle {
24814            self.last_focused_descendant = Some(event.blurred);
24815        }
24816        self.selection_drag_state = SelectionDragState::None;
24817        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
24818    }
24819
24820    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24821        self.blink_manager.update(cx, BlinkManager::disable);
24822        self.buffer
24823            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
24824
24825        if let Some(blame) = self.blame.as_ref() {
24826            blame.update(cx, GitBlame::blur)
24827        }
24828        if !self.hover_state.focused(window, cx) {
24829            hide_hover(self, cx);
24830        }
24831        if !self
24832            .context_menu
24833            .borrow()
24834            .as_ref()
24835            .is_some_and(|context_menu| context_menu.focused(window, cx))
24836        {
24837            self.hide_context_menu(window, cx);
24838        }
24839        self.take_active_edit_prediction(cx);
24840        cx.emit(EditorEvent::Blurred);
24841        cx.notify();
24842    }
24843
24844    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24845        let mut pending: String = window
24846            .pending_input_keystrokes()
24847            .into_iter()
24848            .flatten()
24849            .filter_map(|keystroke| keystroke.key_char.clone())
24850            .collect();
24851
24852        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
24853            pending = "".to_string();
24854        }
24855
24856        let existing_pending = self
24857            .text_highlights(HighlightKey::PendingInput, cx)
24858            .map(|(_, ranges)| ranges.to_vec());
24859        if existing_pending.is_none() && pending.is_empty() {
24860            return;
24861        }
24862        let transaction =
24863            self.transact(window, cx, |this, window, cx| {
24864                let selections = this
24865                    .selections
24866                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
24867                let edits = selections
24868                    .iter()
24869                    .map(|selection| (selection.end..selection.end, pending.clone()));
24870                this.edit(edits, cx);
24871                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24872                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
24873                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
24874                    }));
24875                });
24876                if let Some(existing_ranges) = existing_pending {
24877                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
24878                    this.edit(edits, cx);
24879                }
24880            });
24881
24882        let snapshot = self.snapshot(window, cx);
24883        let ranges = self
24884            .selections
24885            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
24886            .into_iter()
24887            .map(|selection| {
24888                snapshot.buffer_snapshot().anchor_after(selection.end)
24889                    ..snapshot
24890                        .buffer_snapshot()
24891                        .anchor_before(selection.end + pending.len())
24892            })
24893            .collect();
24894
24895        if pending.is_empty() {
24896            self.clear_highlights(HighlightKey::PendingInput, cx);
24897        } else {
24898            self.highlight_text(
24899                HighlightKey::PendingInput,
24900                ranges,
24901                HighlightStyle {
24902                    underline: Some(UnderlineStyle {
24903                        thickness: px(1.),
24904                        color: None,
24905                        wavy: false,
24906                    }),
24907                    ..Default::default()
24908                },
24909                cx,
24910            );
24911        }
24912
24913        self.ime_transaction = self.ime_transaction.or(transaction);
24914        if let Some(transaction) = self.ime_transaction {
24915            self.buffer.update(cx, |buffer, cx| {
24916                buffer.group_until_transaction(transaction, cx);
24917            });
24918        }
24919
24920        if self
24921            .text_highlights(HighlightKey::PendingInput, cx)
24922            .is_none()
24923        {
24924            self.ime_transaction.take();
24925        }
24926    }
24927
24928    pub fn register_action_renderer(
24929        &mut self,
24930        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
24931    ) -> Subscription {
24932        let id = self.next_editor_action_id.post_inc();
24933        self.editor_actions
24934            .borrow_mut()
24935            .insert(id, Box::new(listener));
24936
24937        let editor_actions = self.editor_actions.clone();
24938        Subscription::new(move || {
24939            editor_actions.borrow_mut().remove(&id);
24940        })
24941    }
24942
24943    pub fn register_action<A: Action>(
24944        &mut self,
24945        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
24946    ) -> Subscription {
24947        let id = self.next_editor_action_id.post_inc();
24948        let listener = Arc::new(listener);
24949        self.editor_actions.borrow_mut().insert(
24950            id,
24951            Box::new(move |_, window, _| {
24952                let listener = listener.clone();
24953                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
24954                    let action = action.downcast_ref().unwrap();
24955                    if phase == DispatchPhase::Bubble {
24956                        listener(action, window, cx)
24957                    }
24958                })
24959            }),
24960        );
24961
24962        let editor_actions = self.editor_actions.clone();
24963        Subscription::new(move || {
24964            editor_actions.borrow_mut().remove(&id);
24965        })
24966    }
24967
24968    pub fn file_header_size(&self) -> u32 {
24969        FILE_HEADER_HEIGHT
24970    }
24971
24972    pub fn restore(
24973        &mut self,
24974        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
24975        window: &mut Window,
24976        cx: &mut Context<Self>,
24977    ) {
24978        self.buffer().update(cx, |multi_buffer, cx| {
24979            for (buffer_id, changes) in revert_changes {
24980                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
24981                    buffer.update(cx, |buffer, cx| {
24982                        buffer.edit(
24983                            changes
24984                                .into_iter()
24985                                .map(|(range, text)| (range, text.to_string())),
24986                            None,
24987                            cx,
24988                        );
24989                    });
24990                }
24991            }
24992        });
24993        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24994            selections.refresh()
24995        });
24996    }
24997
24998    pub fn to_pixel_point(
24999        &mut self,
25000        source: Anchor,
25001        editor_snapshot: &EditorSnapshot,
25002        window: &mut Window,
25003        cx: &mut App,
25004    ) -> Option<gpui::Point<Pixels>> {
25005        let source_point = source.to_display_point(editor_snapshot);
25006        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25007    }
25008
25009    pub fn display_to_pixel_point(
25010        &mut self,
25011        source: DisplayPoint,
25012        editor_snapshot: &EditorSnapshot,
25013        window: &mut Window,
25014        cx: &mut App,
25015    ) -> Option<gpui::Point<Pixels>> {
25016        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25017        let text_layout_details = self.text_layout_details(window, cx);
25018        let scroll_top = text_layout_details
25019            .scroll_anchor
25020            .scroll_position(editor_snapshot)
25021            .y;
25022
25023        if source.row().as_f64() < scroll_top.floor() {
25024            return None;
25025        }
25026        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25027        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25028        Some(gpui::Point::new(source_x, source_y))
25029    }
25030
25031    pub fn has_visible_completions_menu(&self) -> bool {
25032        !self.edit_prediction_preview_is_active()
25033            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25034                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25035            })
25036    }
25037
25038    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25039        if self.mode.is_minimap() {
25040            return;
25041        }
25042        self.addons
25043            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25044    }
25045
25046    pub fn unregister_addon<T: Addon>(&mut self) {
25047        self.addons.remove(&std::any::TypeId::of::<T>());
25048    }
25049
25050    pub fn addon<T: Addon>(&self) -> Option<&T> {
25051        let type_id = std::any::TypeId::of::<T>();
25052        self.addons
25053            .get(&type_id)
25054            .and_then(|item| item.to_any().downcast_ref::<T>())
25055    }
25056
25057    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25058        let type_id = std::any::TypeId::of::<T>();
25059        self.addons
25060            .get_mut(&type_id)
25061            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25062    }
25063
25064    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25065        let text_layout_details = self.text_layout_details(window, cx);
25066        let style = &text_layout_details.editor_style;
25067        let font_id = window.text_system().resolve_font(&style.text.font());
25068        let font_size = style.text.font_size.to_pixels(window.rem_size());
25069        let line_height = style.text.line_height_in_pixels(window.rem_size());
25070        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25071        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25072
25073        CharacterDimensions {
25074            em_width,
25075            em_advance,
25076            line_height,
25077        }
25078    }
25079
25080    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25081        self.load_diff_task.clone()
25082    }
25083
25084    fn read_metadata_from_db(
25085        &mut self,
25086        item_id: u64,
25087        workspace_id: WorkspaceId,
25088        window: &mut Window,
25089        cx: &mut Context<Editor>,
25090    ) {
25091        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25092            && !self.mode.is_minimap()
25093            && WorkspaceSettings::get(None, cx).restore_on_startup
25094                != RestoreOnStartupBehavior::EmptyTab
25095        {
25096            let buffer_snapshot = OnceCell::new();
25097
25098            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
25099                && !folds.is_empty()
25100            {
25101                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25102                let snapshot_len = snapshot.len().0;
25103
25104                // Helper: search for fingerprint in buffer, return offset if found
25105                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25106                    // Ensure we start at a character boundary (defensive)
25107                    let search_start = snapshot
25108                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25109                        .0;
25110                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25111
25112                    let mut byte_offset = search_start;
25113                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25114                        if byte_offset > search_end {
25115                            break;
25116                        }
25117                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25118                            return Some(byte_offset);
25119                        }
25120                        byte_offset += ch.len_utf8();
25121                    }
25122                    None
25123                };
25124
25125                // Track search position to handle duplicate fingerprints correctly.
25126                // Folds are stored in document order, so we advance after each match.
25127                let mut search_start = 0usize;
25128
25129                let valid_folds: Vec<_> = folds
25130                    .into_iter()
25131                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25132                        // Skip folds without fingerprints (old data before migration)
25133                        let sfp = start_fp?;
25134                        let efp = end_fp?;
25135                        let efp_len = efp.len();
25136
25137                        // Fast path: check if fingerprints match at stored offsets
25138                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25139                        let start_matches = stored_start < snapshot_len
25140                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25141                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25142                        let end_matches = efp_check_pos >= stored_start
25143                            && stored_end <= snapshot_len
25144                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25145
25146                        let (new_start, new_end) = if start_matches && end_matches {
25147                            // Offsets unchanged, use stored values
25148                            (stored_start, stored_end)
25149                        } else if sfp == efp {
25150                            // Short fold: identical fingerprints can only match once per search
25151                            // Use stored fold length to compute new_end
25152                            let new_start = find_fingerprint(&sfp, search_start)?;
25153                            let fold_len = stored_end - stored_start;
25154                            let new_end = new_start + fold_len;
25155                            (new_start, new_end)
25156                        } else {
25157                            // Slow path: search for fingerprints in buffer
25158                            let new_start = find_fingerprint(&sfp, search_start)?;
25159                            // Search for end_fp after start, then add efp_len to get actual fold end
25160                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25161                            let new_end = efp_pos + efp_len;
25162                            (new_start, new_end)
25163                        };
25164
25165                        // Advance search position for next fold
25166                        search_start = new_end;
25167
25168                        // Validate fold makes sense (end must be after start)
25169                        if new_end <= new_start {
25170                            return None;
25171                        }
25172
25173                        Some(
25174                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25175                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25176                        )
25177                    })
25178                    .collect();
25179
25180                if !valid_folds.is_empty() {
25181                    self.fold_ranges(valid_folds, false, window, cx);
25182
25183                    // Migrate folds to current entity_id before workspace cleanup runs.
25184                    // Entity IDs change between sessions, but workspace cleanup deletes
25185                    // old editor rows (cascading to folds) based on current entity IDs.
25186                    let new_editor_id = cx.entity().entity_id().as_u64() as ItemId;
25187                    if new_editor_id != item_id {
25188                        cx.spawn(async move |_, _| {
25189                            DB.migrate_editor_folds(item_id, new_editor_id, workspace_id)
25190                                .await
25191                                .log_err();
25192                        })
25193                        .detach();
25194                    }
25195                }
25196            }
25197
25198            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
25199                && !selections.is_empty()
25200            {
25201                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25202                // skip adding the initial selection to selection history
25203                self.selection_history.mode = SelectionHistoryMode::Skipping;
25204                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25205                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25206                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25207                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25208                    }));
25209                });
25210                self.selection_history.mode = SelectionHistoryMode::Normal;
25211            };
25212        }
25213
25214        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25215    }
25216
25217    fn update_lsp_data(
25218        &mut self,
25219        for_buffer: Option<BufferId>,
25220        window: &mut Window,
25221        cx: &mut Context<'_, Self>,
25222    ) {
25223        if !self.enable_lsp_data {
25224            return;
25225        }
25226
25227        if let Some(buffer_id) = for_buffer {
25228            self.pull_diagnostics(buffer_id, window, cx);
25229            self.update_semantic_tokens(Some(buffer_id), None, cx);
25230        } else {
25231            self.refresh_semantic_token_highlights(cx);
25232        }
25233        self.refresh_colors_for_visible_range(for_buffer, window, cx);
25234        self.refresh_folding_ranges(for_buffer, window, cx);
25235    }
25236
25237    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25238        if !self.mode().is_full() {
25239            return;
25240        }
25241        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
25242            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25243        }
25244    }
25245
25246    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25247        if !self.mode().is_full() {
25248            return;
25249        }
25250
25251        if !self.registered_buffers.contains_key(&buffer_id)
25252            && let Some(project) = self.project.as_ref()
25253        {
25254            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25255                project.update(cx, |project, cx| {
25256                    self.registered_buffers.insert(
25257                        buffer_id,
25258                        project.register_buffer_with_language_servers(&buffer, cx),
25259                    );
25260                });
25261            } else {
25262                self.registered_buffers.remove(&buffer_id);
25263            }
25264        }
25265    }
25266
25267    fn create_style(&self, cx: &App) -> EditorStyle {
25268        let settings = ThemeSettings::get_global(cx);
25269
25270        let mut text_style = match self.mode {
25271            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25272                color: cx.theme().colors().editor_foreground,
25273                font_family: settings.ui_font.family.clone(),
25274                font_features: settings.ui_font.features.clone(),
25275                font_fallbacks: settings.ui_font.fallbacks.clone(),
25276                font_size: rems(0.875).into(),
25277                font_weight: settings.ui_font.weight,
25278                line_height: relative(settings.buffer_line_height.value()),
25279                ..Default::default()
25280            },
25281            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25282                color: cx.theme().colors().editor_foreground,
25283                font_family: settings.buffer_font.family.clone(),
25284                font_features: settings.buffer_font.features.clone(),
25285                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25286                font_size: settings.buffer_font_size(cx).into(),
25287                font_weight: settings.buffer_font.weight,
25288                line_height: relative(settings.buffer_line_height.value()),
25289                ..Default::default()
25290            },
25291        };
25292        if let Some(text_style_refinement) = &self.text_style_refinement {
25293            text_style.refine(text_style_refinement)
25294        }
25295
25296        let background = match self.mode {
25297            EditorMode::SingleLine => cx.theme().system().transparent,
25298            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25299            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25300            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25301        };
25302
25303        EditorStyle {
25304            background,
25305            border: cx.theme().colors().border,
25306            local_player: cx.theme().players().local(),
25307            text: text_style,
25308            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25309            syntax: cx.theme().syntax().clone(),
25310            status: cx.theme().status().clone(),
25311            inlay_hints_style: make_inlay_hints_style(cx),
25312            edit_prediction_styles: make_suggestion_styles(cx),
25313            unnecessary_code_fade: settings.unnecessary_code_fade,
25314            show_underlines: self.diagnostics_enabled(),
25315        }
25316    }
25317    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<BreadcrumbText>> {
25318        let multibuffer = self.buffer().read(cx);
25319        let is_singleton = multibuffer.is_singleton();
25320        let (buffer_id, symbols) = self.outline_symbols.as_ref()?;
25321        let buffer = multibuffer.buffer(*buffer_id)?;
25322
25323        let buffer = buffer.read(cx);
25324        let settings = ThemeSettings::get_global(cx);
25325        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25326        let mut breadcrumbs = if is_singleton {
25327            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25328                buffer
25329                    .snapshot()
25330                    .resolve_file_path(
25331                        self.project
25332                            .as_ref()
25333                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25334                            .unwrap_or_default(),
25335                        cx,
25336                    )
25337                    .unwrap_or_else(|| {
25338                        if multibuffer.is_singleton() {
25339                            multibuffer.title(cx).to_string()
25340                        } else {
25341                            "untitled".to_string()
25342                        }
25343                    })
25344            });
25345            vec![BreadcrumbText {
25346                text,
25347                highlights: None,
25348                font: Some(settings.buffer_font.clone()),
25349            }]
25350        } else {
25351            vec![]
25352        };
25353
25354        breadcrumbs.extend(symbols.iter().map(|symbol| BreadcrumbText {
25355            text: symbol.text.clone(),
25356            highlights: Some(symbol.highlight_ranges.clone()),
25357            font: Some(settings.buffer_font.clone()),
25358        }));
25359        Some(breadcrumbs)
25360    }
25361
25362    fn disable_lsp_data(&mut self) {
25363        self.enable_lsp_data = false;
25364    }
25365
25366    fn disable_runnables(&mut self) {
25367        self.enable_runnables = false;
25368    }
25369}
25370
25371fn edit_for_markdown_paste<'a>(
25372    buffer: &MultiBufferSnapshot,
25373    range: Range<MultiBufferOffset>,
25374    to_insert: &'a str,
25375    url: Option<url::Url>,
25376) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25377    if url.is_none() {
25378        return (range, Cow::Borrowed(to_insert));
25379    };
25380
25381    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25382
25383    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25384        Cow::Borrowed(to_insert)
25385    } else {
25386        Cow::Owned(format!("[{old_text}]({to_insert})"))
25387    };
25388    (range, new_text)
25389}
25390
25391fn process_completion_for_edit(
25392    completion: &Completion,
25393    intent: CompletionIntent,
25394    buffer: &Entity<Buffer>,
25395    cursor_position: &text::Anchor,
25396    cx: &mut Context<Editor>,
25397) -> CompletionEdit {
25398    let buffer = buffer.read(cx);
25399    let buffer_snapshot = buffer.snapshot();
25400    let (snippet, new_text) = if completion.is_snippet() {
25401        let mut snippet_source = completion.new_text.clone();
25402        // Workaround for typescript language server issues so that methods don't expand within
25403        // strings and functions with type expressions. The previous point is used because the query
25404        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25405        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25406        let previous_point = if previous_point.column > 0 {
25407            cursor_position.to_previous_offset(&buffer_snapshot)
25408        } else {
25409            cursor_position.to_offset(&buffer_snapshot)
25410        };
25411        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25412            && scope.prefers_label_for_snippet_in_completion()
25413            && let Some(label) = completion.label()
25414            && matches!(
25415                completion.kind(),
25416                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25417            )
25418        {
25419            snippet_source = label;
25420        }
25421        match Snippet::parse(&snippet_source).log_err() {
25422            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25423            None => (None, completion.new_text.clone()),
25424        }
25425    } else {
25426        (None, completion.new_text.clone())
25427    };
25428
25429    let mut range_to_replace = {
25430        let replace_range = &completion.replace_range;
25431        if let CompletionSource::Lsp {
25432            insert_range: Some(insert_range),
25433            ..
25434        } = &completion.source
25435        {
25436            debug_assert_eq!(
25437                insert_range.start, replace_range.start,
25438                "insert_range and replace_range should start at the same position"
25439            );
25440            debug_assert!(
25441                insert_range
25442                    .start
25443                    .cmp(cursor_position, &buffer_snapshot)
25444                    .is_le(),
25445                "insert_range should start before or at cursor position"
25446            );
25447            debug_assert!(
25448                replace_range
25449                    .start
25450                    .cmp(cursor_position, &buffer_snapshot)
25451                    .is_le(),
25452                "replace_range should start before or at cursor position"
25453            );
25454
25455            let should_replace = match intent {
25456                CompletionIntent::CompleteWithInsert => false,
25457                CompletionIntent::CompleteWithReplace => true,
25458                CompletionIntent::Complete | CompletionIntent::Compose => {
25459                    let insert_mode =
25460                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
25461                            .completions
25462                            .lsp_insert_mode;
25463                    match insert_mode {
25464                        LspInsertMode::Insert => false,
25465                        LspInsertMode::Replace => true,
25466                        LspInsertMode::ReplaceSubsequence => {
25467                            let mut text_to_replace = buffer.chars_for_range(
25468                                buffer.anchor_before(replace_range.start)
25469                                    ..buffer.anchor_after(replace_range.end),
25470                            );
25471                            let mut current_needle = text_to_replace.next();
25472                            for haystack_ch in completion.label.text.chars() {
25473                                if let Some(needle_ch) = current_needle
25474                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25475                                {
25476                                    current_needle = text_to_replace.next();
25477                                }
25478                            }
25479                            current_needle.is_none()
25480                        }
25481                        LspInsertMode::ReplaceSuffix => {
25482                            if replace_range
25483                                .end
25484                                .cmp(cursor_position, &buffer_snapshot)
25485                                .is_gt()
25486                            {
25487                                let range_after_cursor = *cursor_position..replace_range.end;
25488                                let text_after_cursor = buffer
25489                                    .text_for_range(
25490                                        buffer.anchor_before(range_after_cursor.start)
25491                                            ..buffer.anchor_after(range_after_cursor.end),
25492                                    )
25493                                    .collect::<String>()
25494                                    .to_ascii_lowercase();
25495                                completion
25496                                    .label
25497                                    .text
25498                                    .to_ascii_lowercase()
25499                                    .ends_with(&text_after_cursor)
25500                            } else {
25501                                true
25502                            }
25503                        }
25504                    }
25505                }
25506            };
25507
25508            if should_replace {
25509                replace_range.clone()
25510            } else {
25511                insert_range.clone()
25512            }
25513        } else {
25514            replace_range.clone()
25515        }
25516    };
25517
25518    if range_to_replace
25519        .end
25520        .cmp(cursor_position, &buffer_snapshot)
25521        .is_lt()
25522    {
25523        range_to_replace.end = *cursor_position;
25524    }
25525
25526    let replace_range = range_to_replace.to_offset(buffer);
25527    CompletionEdit {
25528        new_text,
25529        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
25530        snippet,
25531    }
25532}
25533
25534struct CompletionEdit {
25535    new_text: String,
25536    replace_range: Range<BufferOffset>,
25537    snippet: Option<Snippet>,
25538}
25539
25540fn comment_delimiter_for_newline(
25541    start_point: &Point,
25542    buffer: &MultiBufferSnapshot,
25543    language: &LanguageScope,
25544) -> Option<Arc<str>> {
25545    let delimiters = language.line_comment_prefixes();
25546    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
25547    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25548
25549    let num_of_whitespaces = snapshot
25550        .chars_for_range(range.clone())
25551        .take_while(|c| c.is_whitespace())
25552        .count();
25553    let comment_candidate = snapshot
25554        .chars_for_range(range.clone())
25555        .skip(num_of_whitespaces)
25556        .take(max_len_of_delimiter)
25557        .collect::<String>();
25558    let (delimiter, trimmed_len) = delimiters
25559        .iter()
25560        .filter_map(|delimiter| {
25561            let prefix = delimiter.trim_end();
25562            if comment_candidate.starts_with(prefix) {
25563                Some((delimiter, prefix.len()))
25564            } else {
25565                None
25566            }
25567        })
25568        .max_by_key(|(_, len)| *len)?;
25569
25570    if let Some(BlockCommentConfig {
25571        start: block_start, ..
25572    }) = language.block_comment()
25573    {
25574        let block_start_trimmed = block_start.trim_end();
25575        if block_start_trimmed.starts_with(delimiter.trim_end()) {
25576            let line_content = snapshot
25577                .chars_for_range(range)
25578                .skip(num_of_whitespaces)
25579                .take(block_start_trimmed.len())
25580                .collect::<String>();
25581
25582            if line_content.starts_with(block_start_trimmed) {
25583                return None;
25584            }
25585        }
25586    }
25587
25588    let cursor_is_placed_after_comment_marker =
25589        num_of_whitespaces + trimmed_len <= start_point.column as usize;
25590    if cursor_is_placed_after_comment_marker {
25591        Some(delimiter.clone())
25592    } else {
25593        None
25594    }
25595}
25596
25597fn documentation_delimiter_for_newline(
25598    start_point: &Point,
25599    buffer: &MultiBufferSnapshot,
25600    language: &LanguageScope,
25601    newline_config: &mut NewlineConfig,
25602) -> Option<Arc<str>> {
25603    let BlockCommentConfig {
25604        start: start_tag,
25605        end: end_tag,
25606        prefix: delimiter,
25607        tab_size: len,
25608    } = language.documentation_comment()?;
25609    let is_within_block_comment = buffer
25610        .language_scope_at(*start_point)
25611        .is_some_and(|scope| scope.override_name() == Some("comment"));
25612    if !is_within_block_comment {
25613        return None;
25614    }
25615
25616    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25617
25618    let num_of_whitespaces = snapshot
25619        .chars_for_range(range.clone())
25620        .take_while(|c| c.is_whitespace())
25621        .count();
25622
25623    // 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.
25624    let column = start_point.column;
25625    let cursor_is_after_start_tag = {
25626        let start_tag_len = start_tag.len();
25627        let start_tag_line = snapshot
25628            .chars_for_range(range.clone())
25629            .skip(num_of_whitespaces)
25630            .take(start_tag_len)
25631            .collect::<String>();
25632        if start_tag_line.starts_with(start_tag.as_ref()) {
25633            num_of_whitespaces + start_tag_len <= column as usize
25634        } else {
25635            false
25636        }
25637    };
25638
25639    let cursor_is_after_delimiter = {
25640        let delimiter_trim = delimiter.trim_end();
25641        let delimiter_line = snapshot
25642            .chars_for_range(range.clone())
25643            .skip(num_of_whitespaces)
25644            .take(delimiter_trim.len())
25645            .collect::<String>();
25646        if delimiter_line.starts_with(delimiter_trim) {
25647            num_of_whitespaces + delimiter_trim.len() <= column as usize
25648        } else {
25649            false
25650        }
25651    };
25652
25653    let mut needs_extra_line = false;
25654    let mut extra_line_additional_indent = IndentSize::spaces(0);
25655
25656    let cursor_is_before_end_tag_if_exists = {
25657        let mut char_position = 0u32;
25658        let mut end_tag_offset = None;
25659
25660        'outer: for chunk in snapshot.text_for_range(range) {
25661            if let Some(byte_pos) = chunk.find(&**end_tag) {
25662                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
25663                end_tag_offset = Some(char_position + chars_before_match);
25664                break 'outer;
25665            }
25666            char_position += chunk.chars().count() as u32;
25667        }
25668
25669        if let Some(end_tag_offset) = end_tag_offset {
25670            let cursor_is_before_end_tag = column <= end_tag_offset;
25671            if cursor_is_after_start_tag {
25672                if cursor_is_before_end_tag {
25673                    needs_extra_line = true;
25674                }
25675                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
25676                if cursor_is_at_start_of_end_tag {
25677                    extra_line_additional_indent.len = *len;
25678                }
25679            }
25680            cursor_is_before_end_tag
25681        } else {
25682            true
25683        }
25684    };
25685
25686    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
25687        && cursor_is_before_end_tag_if_exists
25688    {
25689        let additional_indent = if cursor_is_after_start_tag {
25690            IndentSize::spaces(*len)
25691        } else {
25692            IndentSize::spaces(0)
25693        };
25694
25695        *newline_config = NewlineConfig::Newline {
25696            additional_indent,
25697            extra_line_additional_indent: if needs_extra_line {
25698                Some(extra_line_additional_indent)
25699            } else {
25700                None
25701            },
25702            prevent_auto_indent: true,
25703        };
25704        Some(delimiter.clone())
25705    } else {
25706        None
25707    }
25708}
25709
25710const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
25711
25712fn list_delimiter_for_newline(
25713    start_point: &Point,
25714    buffer: &MultiBufferSnapshot,
25715    language: &LanguageScope,
25716    newline_config: &mut NewlineConfig,
25717) -> Option<Arc<str>> {
25718    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25719
25720    let num_of_whitespaces = snapshot
25721        .chars_for_range(range.clone())
25722        .take_while(|c| c.is_whitespace())
25723        .count();
25724
25725    let task_list_entries: Vec<_> = language
25726        .task_list()
25727        .into_iter()
25728        .flat_map(|config| {
25729            config
25730                .prefixes
25731                .iter()
25732                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
25733        })
25734        .collect();
25735    let unordered_list_entries: Vec<_> = language
25736        .unordered_list()
25737        .iter()
25738        .map(|marker| (marker.as_ref(), marker.as_ref()))
25739        .collect();
25740
25741    let all_entries: Vec<_> = task_list_entries
25742        .into_iter()
25743        .chain(unordered_list_entries)
25744        .collect();
25745
25746    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
25747        let candidate: String = snapshot
25748            .chars_for_range(range.clone())
25749            .skip(num_of_whitespaces)
25750            .take(max_prefix_len)
25751            .collect();
25752
25753        if let Some((prefix, continuation)) = all_entries
25754            .iter()
25755            .filter(|(prefix, _)| candidate.starts_with(*prefix))
25756            .max_by_key(|(prefix, _)| prefix.len())
25757        {
25758            let end_of_prefix = num_of_whitespaces + prefix.len();
25759            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25760            let has_content_after_marker = snapshot
25761                .chars_for_range(range)
25762                .skip(end_of_prefix)
25763                .any(|c| !c.is_whitespace());
25764
25765            if has_content_after_marker && cursor_is_after_prefix {
25766                return Some((*continuation).into());
25767            }
25768
25769            if start_point.column as usize == end_of_prefix {
25770                if num_of_whitespaces == 0 {
25771                    *newline_config = NewlineConfig::ClearCurrentLine;
25772                } else {
25773                    *newline_config = NewlineConfig::UnindentCurrentLine {
25774                        continuation: (*continuation).into(),
25775                    };
25776                }
25777            }
25778
25779            return None;
25780        }
25781    }
25782
25783    let candidate: String = snapshot
25784        .chars_for_range(range.clone())
25785        .skip(num_of_whitespaces)
25786        .take(ORDERED_LIST_MAX_MARKER_LEN)
25787        .collect();
25788
25789    for ordered_config in language.ordered_list() {
25790        let regex = match Regex::new(&ordered_config.pattern) {
25791            Ok(r) => r,
25792            Err(_) => continue,
25793        };
25794
25795        if let Some(captures) = regex.captures(&candidate) {
25796            let full_match = captures.get(0)?;
25797            let marker_len = full_match.len();
25798            let end_of_prefix = num_of_whitespaces + marker_len;
25799            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25800
25801            let has_content_after_marker = snapshot
25802                .chars_for_range(range)
25803                .skip(end_of_prefix)
25804                .any(|c| !c.is_whitespace());
25805
25806            if has_content_after_marker && cursor_is_after_prefix {
25807                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
25808                let continuation = ordered_config
25809                    .format
25810                    .replace("{1}", &(number + 1).to_string());
25811                return Some(continuation.into());
25812            }
25813
25814            if start_point.column as usize == end_of_prefix {
25815                let continuation = ordered_config.format.replace("{1}", "1");
25816                if num_of_whitespaces == 0 {
25817                    *newline_config = NewlineConfig::ClearCurrentLine;
25818                } else {
25819                    *newline_config = NewlineConfig::UnindentCurrentLine {
25820                        continuation: continuation.into(),
25821                    };
25822                }
25823            }
25824
25825            return None;
25826        }
25827    }
25828
25829    None
25830}
25831
25832fn is_list_prefix_row(
25833    row: MultiBufferRow,
25834    buffer: &MultiBufferSnapshot,
25835    language: &LanguageScope,
25836) -> bool {
25837    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
25838        return false;
25839    };
25840
25841    let num_of_whitespaces = snapshot
25842        .chars_for_range(range.clone())
25843        .take_while(|c| c.is_whitespace())
25844        .count();
25845
25846    let task_list_prefixes: Vec<_> = language
25847        .task_list()
25848        .into_iter()
25849        .flat_map(|config| {
25850            config
25851                .prefixes
25852                .iter()
25853                .map(|p| p.as_ref())
25854                .collect::<Vec<_>>()
25855        })
25856        .collect();
25857    let unordered_list_markers: Vec<_> = language
25858        .unordered_list()
25859        .iter()
25860        .map(|marker| marker.as_ref())
25861        .collect();
25862    let all_prefixes: Vec<_> = task_list_prefixes
25863        .into_iter()
25864        .chain(unordered_list_markers)
25865        .collect();
25866    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
25867        let candidate: String = snapshot
25868            .chars_for_range(range.clone())
25869            .skip(num_of_whitespaces)
25870            .take(max_prefix_len)
25871            .collect();
25872        if all_prefixes
25873            .iter()
25874            .any(|prefix| candidate.starts_with(*prefix))
25875        {
25876            return true;
25877        }
25878    }
25879
25880    let ordered_list_candidate: String = snapshot
25881        .chars_for_range(range)
25882        .skip(num_of_whitespaces)
25883        .take(ORDERED_LIST_MAX_MARKER_LEN)
25884        .collect();
25885    for ordered_config in language.ordered_list() {
25886        let regex = match Regex::new(&ordered_config.pattern) {
25887            Ok(r) => r,
25888            Err(_) => continue,
25889        };
25890        if let Some(captures) = regex.captures(&ordered_list_candidate) {
25891            return captures.get(0).is_some();
25892        }
25893    }
25894
25895    false
25896}
25897
25898#[derive(Debug)]
25899enum NewlineConfig {
25900    /// Insert newline with optional additional indent and optional extra blank line
25901    Newline {
25902        additional_indent: IndentSize,
25903        extra_line_additional_indent: Option<IndentSize>,
25904        prevent_auto_indent: bool,
25905    },
25906    /// Clear the current line
25907    ClearCurrentLine,
25908    /// Unindent the current line and add continuation
25909    UnindentCurrentLine { continuation: Arc<str> },
25910}
25911
25912impl NewlineConfig {
25913    fn has_extra_line(&self) -> bool {
25914        matches!(
25915            self,
25916            Self::Newline {
25917                extra_line_additional_indent: Some(_),
25918                ..
25919            }
25920        )
25921    }
25922
25923    fn insert_extra_newline_brackets(
25924        buffer: &MultiBufferSnapshot,
25925        range: Range<MultiBufferOffset>,
25926        language: &language::LanguageScope,
25927    ) -> bool {
25928        let leading_whitespace_len = buffer
25929            .reversed_chars_at(range.start)
25930            .take_while(|c| c.is_whitespace() && *c != '\n')
25931            .map(|c| c.len_utf8())
25932            .sum::<usize>();
25933        let trailing_whitespace_len = buffer
25934            .chars_at(range.end)
25935            .take_while(|c| c.is_whitespace() && *c != '\n')
25936            .map(|c| c.len_utf8())
25937            .sum::<usize>();
25938        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
25939
25940        language.brackets().any(|(pair, enabled)| {
25941            let pair_start = pair.start.trim_end();
25942            let pair_end = pair.end.trim_start();
25943
25944            enabled
25945                && pair.newline
25946                && buffer.contains_str_at(range.end, pair_end)
25947                && buffer.contains_str_at(
25948                    range.start.saturating_sub_usize(pair_start.len()),
25949                    pair_start,
25950                )
25951        })
25952    }
25953
25954    fn insert_extra_newline_tree_sitter(
25955        buffer: &MultiBufferSnapshot,
25956        range: Range<MultiBufferOffset>,
25957    ) -> bool {
25958        let (buffer, range) = match buffer
25959            .range_to_buffer_ranges(range.start..=range.end)
25960            .as_slice()
25961        {
25962            [(buffer, range, _)] => (*buffer, range.clone()),
25963            _ => return false,
25964        };
25965        let pair = {
25966            let mut result: Option<BracketMatch<usize>> = None;
25967
25968            for pair in buffer
25969                .all_bracket_ranges(range.start.0..range.end.0)
25970                .filter(move |pair| {
25971                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
25972                })
25973            {
25974                let len = pair.close_range.end - pair.open_range.start;
25975
25976                if let Some(existing) = &result {
25977                    let existing_len = existing.close_range.end - existing.open_range.start;
25978                    if len > existing_len {
25979                        continue;
25980                    }
25981                }
25982
25983                result = Some(pair);
25984            }
25985
25986            result
25987        };
25988        let Some(pair) = pair else {
25989            return false;
25990        };
25991        pair.newline_only
25992            && buffer
25993                .chars_for_range(pair.open_range.end..range.start.0)
25994                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
25995                .all(|c| c.is_whitespace() && c != '\n')
25996    }
25997}
25998
25999fn update_uncommitted_diff_for_buffer(
26000    editor: Entity<Editor>,
26001    project: &Entity<Project>,
26002    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26003    buffer: Entity<MultiBuffer>,
26004    cx: &mut App,
26005) -> Task<()> {
26006    let mut tasks = Vec::new();
26007    project.update(cx, |project, cx| {
26008        for buffer in buffers {
26009            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26010                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26011            }
26012        }
26013    });
26014    cx.spawn(async move |cx| {
26015        let diffs = future::join_all(tasks).await;
26016        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26017            return;
26018        }
26019
26020        buffer.update(cx, |buffer, cx| {
26021            for diff in diffs.into_iter().flatten() {
26022                buffer.add_diff(diff, cx);
26023            }
26024        });
26025    })
26026}
26027
26028fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26029    let tab_size = tab_size.get() as usize;
26030    let mut width = offset;
26031
26032    for ch in text.chars() {
26033        width += if ch == '\t' {
26034            tab_size - (width % tab_size)
26035        } else {
26036            1
26037        };
26038    }
26039
26040    width - offset
26041}
26042
26043#[cfg(test)]
26044mod tests {
26045    use super::*;
26046
26047    #[test]
26048    fn test_string_size_with_expanded_tabs() {
26049        let nz = |val| NonZeroU32::new(val).unwrap();
26050        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26051        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26052        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26053        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26054        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26055        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26056        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26057        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26058    }
26059}
26060
26061/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26062struct WordBreakingTokenizer<'a> {
26063    input: &'a str,
26064}
26065
26066impl<'a> WordBreakingTokenizer<'a> {
26067    fn new(input: &'a str) -> Self {
26068        Self { input }
26069    }
26070}
26071
26072fn is_char_ideographic(ch: char) -> bool {
26073    use unicode_script::Script::*;
26074    use unicode_script::UnicodeScript;
26075    matches!(ch.script(), Han | Tangut | Yi)
26076}
26077
26078fn is_grapheme_ideographic(text: &str) -> bool {
26079    text.chars().any(is_char_ideographic)
26080}
26081
26082fn is_grapheme_whitespace(text: &str) -> bool {
26083    text.chars().any(|x| x.is_whitespace())
26084}
26085
26086fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26087    text.chars()
26088        .next()
26089        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26090}
26091
26092#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26093enum WordBreakToken<'a> {
26094    Word { token: &'a str, grapheme_len: usize },
26095    InlineWhitespace { token: &'a str, grapheme_len: usize },
26096    Newline,
26097}
26098
26099impl<'a> Iterator for WordBreakingTokenizer<'a> {
26100    /// Yields a span, the count of graphemes in the token, and whether it was
26101    /// whitespace. Note that it also breaks at word boundaries.
26102    type Item = WordBreakToken<'a>;
26103
26104    fn next(&mut self) -> Option<Self::Item> {
26105        use unicode_segmentation::UnicodeSegmentation;
26106        if self.input.is_empty() {
26107            return None;
26108        }
26109
26110        let mut iter = self.input.graphemes(true).peekable();
26111        let mut offset = 0;
26112        let mut grapheme_len = 0;
26113        if let Some(first_grapheme) = iter.next() {
26114            let is_newline = first_grapheme == "\n";
26115            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26116            offset += first_grapheme.len();
26117            grapheme_len += 1;
26118            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26119                if let Some(grapheme) = iter.peek().copied()
26120                    && should_stay_with_preceding_ideograph(grapheme)
26121                {
26122                    offset += grapheme.len();
26123                    grapheme_len += 1;
26124                }
26125            } else {
26126                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26127                let mut next_word_bound = words.peek().copied();
26128                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26129                    next_word_bound = words.next();
26130                }
26131                while let Some(grapheme) = iter.peek().copied() {
26132                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26133                        break;
26134                    };
26135                    if is_grapheme_whitespace(grapheme) != is_whitespace
26136                        || (grapheme == "\n") != is_newline
26137                    {
26138                        break;
26139                    };
26140                    offset += grapheme.len();
26141                    grapheme_len += 1;
26142                    iter.next();
26143                }
26144            }
26145            let token = &self.input[..offset];
26146            self.input = &self.input[offset..];
26147            if token == "\n" {
26148                Some(WordBreakToken::Newline)
26149            } else if is_whitespace {
26150                Some(WordBreakToken::InlineWhitespace {
26151                    token,
26152                    grapheme_len,
26153                })
26154            } else {
26155                Some(WordBreakToken::Word {
26156                    token,
26157                    grapheme_len,
26158                })
26159            }
26160        } else {
26161            None
26162        }
26163    }
26164}
26165
26166#[test]
26167fn test_word_breaking_tokenizer() {
26168    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26169        ("", &[]),
26170        ("  ", &[whitespace("  ", 2)]),
26171        ("Ʒ", &[word("Ʒ", 1)]),
26172        ("Ǽ", &[word("Ǽ", 1)]),
26173        ("", &[word("", 1)]),
26174        ("⋑⋑", &[word("⋑⋑", 2)]),
26175        (
26176            "原理,进而",
26177            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26178        ),
26179        (
26180            "hello world",
26181            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26182        ),
26183        (
26184            "hello, world",
26185            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26186        ),
26187        (
26188            "  hello world",
26189            &[
26190                whitespace("  ", 2),
26191                word("hello", 5),
26192                whitespace(" ", 1),
26193                word("world", 5),
26194            ],
26195        ),
26196        (
26197            "这是什么 \n 钢笔",
26198            &[
26199                word("", 1),
26200                word("", 1),
26201                word("", 1),
26202                word("", 1),
26203                whitespace(" ", 1),
26204                newline(),
26205                whitespace(" ", 1),
26206                word("", 1),
26207                word("", 1),
26208            ],
26209        ),
26210        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26211    ];
26212
26213    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26214        WordBreakToken::Word {
26215            token,
26216            grapheme_len,
26217        }
26218    }
26219
26220    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26221        WordBreakToken::InlineWhitespace {
26222            token,
26223            grapheme_len,
26224        }
26225    }
26226
26227    fn newline() -> WordBreakToken<'static> {
26228        WordBreakToken::Newline
26229    }
26230
26231    for (input, result) in tests {
26232        assert_eq!(
26233            WordBreakingTokenizer::new(input)
26234                .collect::<Vec<_>>()
26235                .as_slice(),
26236            *result,
26237        );
26238    }
26239}
26240
26241fn wrap_with_prefix(
26242    first_line_prefix: String,
26243    subsequent_lines_prefix: String,
26244    unwrapped_text: String,
26245    wrap_column: usize,
26246    tab_size: NonZeroU32,
26247    preserve_existing_whitespace: bool,
26248) -> String {
26249    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
26250    let subsequent_lines_prefix_len =
26251        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
26252    let mut wrapped_text = String::new();
26253    let mut current_line = first_line_prefix;
26254    let mut is_first_line = true;
26255
26256    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
26257    let mut current_line_len = first_line_prefix_len;
26258    let mut in_whitespace = false;
26259    for token in tokenizer {
26260        let have_preceding_whitespace = in_whitespace;
26261        match token {
26262            WordBreakToken::Word {
26263                token,
26264                grapheme_len,
26265            } => {
26266                in_whitespace = false;
26267                let current_prefix_len = if is_first_line {
26268                    first_line_prefix_len
26269                } else {
26270                    subsequent_lines_prefix_len
26271                };
26272                if current_line_len + grapheme_len > wrap_column
26273                    && current_line_len != current_prefix_len
26274                {
26275                    wrapped_text.push_str(current_line.trim_end());
26276                    wrapped_text.push('\n');
26277                    is_first_line = false;
26278                    current_line = subsequent_lines_prefix.clone();
26279                    current_line_len = subsequent_lines_prefix_len;
26280                }
26281                current_line.push_str(token);
26282                current_line_len += grapheme_len;
26283            }
26284            WordBreakToken::InlineWhitespace {
26285                mut token,
26286                mut grapheme_len,
26287            } => {
26288                in_whitespace = true;
26289                if have_preceding_whitespace && !preserve_existing_whitespace {
26290                    continue;
26291                }
26292                if !preserve_existing_whitespace {
26293                    // Keep a single whitespace grapheme as-is
26294                    if let Some(first) =
26295                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
26296                    {
26297                        token = first;
26298                    } else {
26299                        token = " ";
26300                    }
26301                    grapheme_len = 1;
26302                }
26303                let current_prefix_len = if is_first_line {
26304                    first_line_prefix_len
26305                } else {
26306                    subsequent_lines_prefix_len
26307                };
26308                if current_line_len + grapheme_len > wrap_column {
26309                    wrapped_text.push_str(current_line.trim_end());
26310                    wrapped_text.push('\n');
26311                    is_first_line = false;
26312                    current_line = subsequent_lines_prefix.clone();
26313                    current_line_len = subsequent_lines_prefix_len;
26314                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
26315                    current_line.push_str(token);
26316                    current_line_len += grapheme_len;
26317                }
26318            }
26319            WordBreakToken::Newline => {
26320                in_whitespace = true;
26321                let current_prefix_len = if is_first_line {
26322                    first_line_prefix_len
26323                } else {
26324                    subsequent_lines_prefix_len
26325                };
26326                if preserve_existing_whitespace {
26327                    wrapped_text.push_str(current_line.trim_end());
26328                    wrapped_text.push('\n');
26329                    is_first_line = false;
26330                    current_line = subsequent_lines_prefix.clone();
26331                    current_line_len = subsequent_lines_prefix_len;
26332                } else if have_preceding_whitespace {
26333                    continue;
26334                } else if current_line_len + 1 > wrap_column
26335                    && current_line_len != current_prefix_len
26336                {
26337                    wrapped_text.push_str(current_line.trim_end());
26338                    wrapped_text.push('\n');
26339                    is_first_line = false;
26340                    current_line = subsequent_lines_prefix.clone();
26341                    current_line_len = subsequent_lines_prefix_len;
26342                } else if current_line_len != current_prefix_len {
26343                    current_line.push(' ');
26344                    current_line_len += 1;
26345                }
26346            }
26347        }
26348    }
26349
26350    if !current_line.is_empty() {
26351        wrapped_text.push_str(&current_line);
26352    }
26353    wrapped_text
26354}
26355
26356#[test]
26357fn test_wrap_with_prefix() {
26358    assert_eq!(
26359        wrap_with_prefix(
26360            "# ".to_string(),
26361            "# ".to_string(),
26362            "abcdefg".to_string(),
26363            4,
26364            NonZeroU32::new(4).unwrap(),
26365            false,
26366        ),
26367        "# abcdefg"
26368    );
26369    assert_eq!(
26370        wrap_with_prefix(
26371            "".to_string(),
26372            "".to_string(),
26373            "\thello world".to_string(),
26374            8,
26375            NonZeroU32::new(4).unwrap(),
26376            false,
26377        ),
26378        "hello\nworld"
26379    );
26380    assert_eq!(
26381        wrap_with_prefix(
26382            "// ".to_string(),
26383            "// ".to_string(),
26384            "xx \nyy zz aa bb cc".to_string(),
26385            12,
26386            NonZeroU32::new(4).unwrap(),
26387            false,
26388        ),
26389        "// xx yy zz\n// aa bb cc"
26390    );
26391    assert_eq!(
26392        wrap_with_prefix(
26393            String::new(),
26394            String::new(),
26395            "这是什么 \n 钢笔".to_string(),
26396            3,
26397            NonZeroU32::new(4).unwrap(),
26398            false,
26399        ),
26400        "这是什\n么 钢\n"
26401    );
26402    assert_eq!(
26403        wrap_with_prefix(
26404            String::new(),
26405            String::new(),
26406            format!("foo{}bar", '\u{2009}'), // thin space
26407            80,
26408            NonZeroU32::new(4).unwrap(),
26409            false,
26410        ),
26411        format!("foo{}bar", '\u{2009}')
26412    );
26413}
26414
26415pub trait CollaborationHub {
26416    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26417    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26418    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26419}
26420
26421impl CollaborationHub for Entity<Project> {
26422    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26423        self.read(cx).collaborators()
26424    }
26425
26426    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26427        self.read(cx).user_store().read(cx).participant_indices()
26428    }
26429
26430    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26431        let this = self.read(cx);
26432        let user_ids = this.collaborators().values().map(|c| c.user_id);
26433        this.user_store().read(cx).participant_names(user_ids, cx)
26434    }
26435}
26436
26437pub trait SemanticsProvider {
26438    fn hover(
26439        &self,
26440        buffer: &Entity<Buffer>,
26441        position: text::Anchor,
26442        cx: &mut App,
26443    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26444
26445    fn inline_values(
26446        &self,
26447        buffer_handle: Entity<Buffer>,
26448        range: Range<text::Anchor>,
26449        cx: &mut App,
26450    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
26451
26452    fn applicable_inlay_chunks(
26453        &self,
26454        buffer: &Entity<Buffer>,
26455        ranges: &[Range<text::Anchor>],
26456        cx: &mut App,
26457    ) -> Vec<Range<BufferRow>>;
26458
26459    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
26460
26461    fn inlay_hints(
26462        &self,
26463        invalidate: InvalidationStrategy,
26464        buffer: Entity<Buffer>,
26465        ranges: Vec<Range<text::Anchor>>,
26466        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26467        cx: &mut App,
26468    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
26469
26470    fn semantic_tokens(
26471        &self,
26472        buffer: Entity<Buffer>,
26473        refresh: Option<RefreshForServer>,
26474        cx: &mut App,
26475    ) -> Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>;
26476
26477    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
26478
26479    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
26480
26481    fn document_highlights(
26482        &self,
26483        buffer: &Entity<Buffer>,
26484        position: text::Anchor,
26485        cx: &mut App,
26486    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
26487
26488    fn definitions(
26489        &self,
26490        buffer: &Entity<Buffer>,
26491        position: text::Anchor,
26492        kind: GotoDefinitionKind,
26493        cx: &mut App,
26494    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
26495
26496    fn range_for_rename(
26497        &self,
26498        buffer: &Entity<Buffer>,
26499        position: text::Anchor,
26500        cx: &mut App,
26501    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
26502
26503    fn perform_rename(
26504        &self,
26505        buffer: &Entity<Buffer>,
26506        position: text::Anchor,
26507        new_name: String,
26508        cx: &mut App,
26509    ) -> Option<Task<Result<ProjectTransaction>>>;
26510}
26511
26512pub trait CompletionProvider {
26513    fn completions(
26514        &self,
26515        excerpt_id: ExcerptId,
26516        buffer: &Entity<Buffer>,
26517        buffer_position: text::Anchor,
26518        trigger: CompletionContext,
26519        window: &mut Window,
26520        cx: &mut Context<Editor>,
26521    ) -> Task<Result<Vec<CompletionResponse>>>;
26522
26523    fn resolve_completions(
26524        &self,
26525        _buffer: Entity<Buffer>,
26526        _completion_indices: Vec<usize>,
26527        _completions: Rc<RefCell<Box<[Completion]>>>,
26528        _cx: &mut Context<Editor>,
26529    ) -> Task<Result<bool>> {
26530        Task::ready(Ok(false))
26531    }
26532
26533    fn apply_additional_edits_for_completion(
26534        &self,
26535        _buffer: Entity<Buffer>,
26536        _completions: Rc<RefCell<Box<[Completion]>>>,
26537        _completion_index: usize,
26538        _push_to_history: bool,
26539        _cx: &mut Context<Editor>,
26540    ) -> Task<Result<Option<language::Transaction>>> {
26541        Task::ready(Ok(None))
26542    }
26543
26544    fn is_completion_trigger(
26545        &self,
26546        buffer: &Entity<Buffer>,
26547        position: language::Anchor,
26548        text: &str,
26549        trigger_in_words: bool,
26550        cx: &mut Context<Editor>,
26551    ) -> bool;
26552
26553    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
26554
26555    fn sort_completions(&self) -> bool {
26556        true
26557    }
26558
26559    fn filter_completions(&self) -> bool {
26560        true
26561    }
26562
26563    fn show_snippets(&self) -> bool {
26564        false
26565    }
26566}
26567
26568pub trait CodeActionProvider {
26569    fn id(&self) -> Arc<str>;
26570
26571    fn code_actions(
26572        &self,
26573        buffer: &Entity<Buffer>,
26574        range: Range<text::Anchor>,
26575        window: &mut Window,
26576        cx: &mut App,
26577    ) -> Task<Result<Vec<CodeAction>>>;
26578
26579    fn apply_code_action(
26580        &self,
26581        buffer_handle: Entity<Buffer>,
26582        action: CodeAction,
26583        excerpt_id: ExcerptId,
26584        push_to_history: bool,
26585        window: &mut Window,
26586        cx: &mut App,
26587    ) -> Task<Result<ProjectTransaction>>;
26588}
26589
26590impl CodeActionProvider for Entity<Project> {
26591    fn id(&self) -> Arc<str> {
26592        "project".into()
26593    }
26594
26595    fn code_actions(
26596        &self,
26597        buffer: &Entity<Buffer>,
26598        range: Range<text::Anchor>,
26599        _window: &mut Window,
26600        cx: &mut App,
26601    ) -> Task<Result<Vec<CodeAction>>> {
26602        self.update(cx, |project, cx| {
26603            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
26604            let code_actions = project.code_actions(buffer, range, None, cx);
26605            cx.background_spawn(async move {
26606                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
26607                Ok(code_lens_actions
26608                    .context("code lens fetch")?
26609                    .into_iter()
26610                    .flatten()
26611                    .chain(
26612                        code_actions
26613                            .context("code action fetch")?
26614                            .into_iter()
26615                            .flatten(),
26616                    )
26617                    .collect())
26618            })
26619        })
26620    }
26621
26622    fn apply_code_action(
26623        &self,
26624        buffer_handle: Entity<Buffer>,
26625        action: CodeAction,
26626        _excerpt_id: ExcerptId,
26627        push_to_history: bool,
26628        _window: &mut Window,
26629        cx: &mut App,
26630    ) -> Task<Result<ProjectTransaction>> {
26631        self.update(cx, |project, cx| {
26632            project.apply_code_action(buffer_handle, action, push_to_history, cx)
26633        })
26634    }
26635}
26636
26637fn snippet_completions(
26638    project: &Project,
26639    buffer: &Entity<Buffer>,
26640    buffer_anchor: text::Anchor,
26641    classifier: CharClassifier,
26642    cx: &mut App,
26643) -> Task<Result<CompletionResponse>> {
26644    let languages = buffer.read(cx).languages_at(buffer_anchor);
26645    let snippet_store = project.snippets().read(cx);
26646
26647    let scopes: Vec<_> = languages
26648        .iter()
26649        .filter_map(|language| {
26650            let language_name = language.lsp_id();
26651            let snippets = snippet_store.snippets_for(Some(language_name), cx);
26652
26653            if snippets.is_empty() {
26654                None
26655            } else {
26656                Some((language.default_scope(), snippets))
26657            }
26658        })
26659        .collect();
26660
26661    if scopes.is_empty() {
26662        return Task::ready(Ok(CompletionResponse {
26663            completions: vec![],
26664            display_options: CompletionDisplayOptions::default(),
26665            is_incomplete: false,
26666        }));
26667    }
26668
26669    let snapshot = buffer.read(cx).text_snapshot();
26670    let executor = cx.background_executor().clone();
26671
26672    cx.background_spawn(async move {
26673        let is_word_char = |c| classifier.is_word(c);
26674
26675        let mut is_incomplete = false;
26676        let mut completions: Vec<Completion> = Vec::new();
26677
26678        const MAX_PREFIX_LEN: usize = 128;
26679        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
26680        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
26681        let window_start = snapshot.clip_offset(window_start, Bias::Left);
26682
26683        let max_buffer_window: String = snapshot
26684            .text_for_range(window_start..buffer_offset)
26685            .collect();
26686
26687        if max_buffer_window.is_empty() {
26688            return Ok(CompletionResponse {
26689                completions: vec![],
26690                display_options: CompletionDisplayOptions::default(),
26691                is_incomplete: true,
26692            });
26693        }
26694
26695        for (_scope, snippets) in scopes.into_iter() {
26696            // Sort snippets by word count to match longer snippet prefixes first.
26697            let mut sorted_snippet_candidates = snippets
26698                .iter()
26699                .enumerate()
26700                .flat_map(|(snippet_ix, snippet)| {
26701                    snippet
26702                        .prefix
26703                        .iter()
26704                        .enumerate()
26705                        .map(move |(prefix_ix, prefix)| {
26706                            let word_count =
26707                                snippet_candidate_suffixes(prefix, is_word_char).count();
26708                            ((snippet_ix, prefix_ix), prefix, word_count)
26709                        })
26710                })
26711                .collect_vec();
26712            sorted_snippet_candidates
26713                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
26714
26715            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
26716
26717            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
26718                .take(
26719                    sorted_snippet_candidates
26720                        .first()
26721                        .map(|(_, _, word_count)| *word_count)
26722                        .unwrap_or_default(),
26723                )
26724                .collect_vec();
26725
26726            const MAX_RESULTS: usize = 100;
26727            // Each match also remembers how many characters from the buffer it consumed
26728            let mut matches: Vec<(StringMatch, usize)> = vec![];
26729
26730            let mut snippet_list_cutoff_index = 0;
26731            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
26732                let word_count = buffer_index + 1;
26733                // Increase `snippet_list_cutoff_index` until we have all of the
26734                // snippets with sufficiently many words.
26735                while sorted_snippet_candidates
26736                    .get(snippet_list_cutoff_index)
26737                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
26738                        *snippet_word_count >= word_count
26739                    })
26740                {
26741                    snippet_list_cutoff_index += 1;
26742                }
26743
26744                // Take only the candidates with at least `word_count` many words
26745                let snippet_candidates_at_word_len =
26746                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
26747
26748                let candidates = snippet_candidates_at_word_len
26749                    .iter()
26750                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
26751                    .enumerate() // index in `sorted_snippet_candidates`
26752                    // First char must match
26753                    .filter(|(_ix, prefix)| {
26754                        itertools::equal(
26755                            prefix
26756                                .chars()
26757                                .next()
26758                                .into_iter()
26759                                .flat_map(|c| c.to_lowercase()),
26760                            buffer_window
26761                                .chars()
26762                                .next()
26763                                .into_iter()
26764                                .flat_map(|c| c.to_lowercase()),
26765                        )
26766                    })
26767                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
26768                    .collect::<Vec<StringMatchCandidate>>();
26769
26770                matches.extend(
26771                    fuzzy::match_strings(
26772                        &candidates,
26773                        &buffer_window,
26774                        buffer_window.chars().any(|c| c.is_uppercase()),
26775                        true,
26776                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
26777                        &Default::default(),
26778                        executor.clone(),
26779                    )
26780                    .await
26781                    .into_iter()
26782                    .map(|string_match| (string_match, buffer_window.len())),
26783                );
26784
26785                if matches.len() >= MAX_RESULTS {
26786                    break;
26787                }
26788            }
26789
26790            let to_lsp = |point: &text::Anchor| {
26791                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
26792                point_to_lsp(end)
26793            };
26794            let lsp_end = to_lsp(&buffer_anchor);
26795
26796            if matches.len() >= MAX_RESULTS {
26797                is_incomplete = true;
26798            }
26799
26800            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
26801                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
26802                    sorted_snippet_candidates[string_match.candidate_id];
26803                let snippet = &snippets[snippet_index];
26804                let start = buffer_offset - buffer_window_len;
26805                let start = snapshot.anchor_before(start);
26806                let range = start..buffer_anchor;
26807                let lsp_start = to_lsp(&start);
26808                let lsp_range = lsp::Range {
26809                    start: lsp_start,
26810                    end: lsp_end,
26811                };
26812                Completion {
26813                    replace_range: range,
26814                    new_text: snippet.body.clone(),
26815                    source: CompletionSource::Lsp {
26816                        insert_range: None,
26817                        server_id: LanguageServerId(usize::MAX),
26818                        resolved: true,
26819                        lsp_completion: Box::new(lsp::CompletionItem {
26820                            label: snippet.prefix.first().unwrap().clone(),
26821                            kind: Some(CompletionItemKind::SNIPPET),
26822                            label_details: snippet.description.as_ref().map(|description| {
26823                                lsp::CompletionItemLabelDetails {
26824                                    detail: Some(description.clone()),
26825                                    description: None,
26826                                }
26827                            }),
26828                            insert_text_format: Some(InsertTextFormat::SNIPPET),
26829                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
26830                                lsp::InsertReplaceEdit {
26831                                    new_text: snippet.body.clone(),
26832                                    insert: lsp_range,
26833                                    replace: lsp_range,
26834                                },
26835                            )),
26836                            filter_text: Some(snippet.body.clone()),
26837                            sort_text: Some(char::MAX.to_string()),
26838                            ..lsp::CompletionItem::default()
26839                        }),
26840                        lsp_defaults: None,
26841                    },
26842                    label: CodeLabel {
26843                        text: matching_prefix.clone(),
26844                        runs: Vec::new(),
26845                        filter_range: 0..matching_prefix.len(),
26846                    },
26847                    icon_path: None,
26848                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
26849                        single_line: snippet.name.clone().into(),
26850                        plain_text: snippet
26851                            .description
26852                            .clone()
26853                            .map(|description| description.into()),
26854                    }),
26855                    insert_text_mode: None,
26856                    confirm: None,
26857                    match_start: Some(start),
26858                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
26859                }
26860            }));
26861        }
26862
26863        Ok(CompletionResponse {
26864            completions,
26865            display_options: CompletionDisplayOptions::default(),
26866            is_incomplete,
26867        })
26868    })
26869}
26870
26871impl CompletionProvider for Entity<Project> {
26872    fn completions(
26873        &self,
26874        _excerpt_id: ExcerptId,
26875        buffer: &Entity<Buffer>,
26876        buffer_position: text::Anchor,
26877        options: CompletionContext,
26878        _window: &mut Window,
26879        cx: &mut Context<Editor>,
26880    ) -> Task<Result<Vec<CompletionResponse>>> {
26881        self.update(cx, |project, cx| {
26882            let task = project.completions(buffer, buffer_position, options, cx);
26883            cx.background_spawn(task)
26884        })
26885    }
26886
26887    fn resolve_completions(
26888        &self,
26889        buffer: Entity<Buffer>,
26890        completion_indices: Vec<usize>,
26891        completions: Rc<RefCell<Box<[Completion]>>>,
26892        cx: &mut Context<Editor>,
26893    ) -> Task<Result<bool>> {
26894        self.update(cx, |project, cx| {
26895            project.lsp_store().update(cx, |lsp_store, cx| {
26896                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
26897            })
26898        })
26899    }
26900
26901    fn apply_additional_edits_for_completion(
26902        &self,
26903        buffer: Entity<Buffer>,
26904        completions: Rc<RefCell<Box<[Completion]>>>,
26905        completion_index: usize,
26906        push_to_history: bool,
26907        cx: &mut Context<Editor>,
26908    ) -> Task<Result<Option<language::Transaction>>> {
26909        self.update(cx, |project, cx| {
26910            project.lsp_store().update(cx, |lsp_store, cx| {
26911                lsp_store.apply_additional_edits_for_completion(
26912                    buffer,
26913                    completions,
26914                    completion_index,
26915                    push_to_history,
26916                    cx,
26917                )
26918            })
26919        })
26920    }
26921
26922    fn is_completion_trigger(
26923        &self,
26924        buffer: &Entity<Buffer>,
26925        position: language::Anchor,
26926        text: &str,
26927        trigger_in_words: bool,
26928        cx: &mut Context<Editor>,
26929    ) -> bool {
26930        let mut chars = text.chars();
26931        let char = if let Some(char) = chars.next() {
26932            char
26933        } else {
26934            return false;
26935        };
26936        if chars.next().is_some() {
26937            return false;
26938        }
26939
26940        let buffer = buffer.read(cx);
26941        let snapshot = buffer.snapshot();
26942        let classifier = snapshot
26943            .char_classifier_at(position)
26944            .scope_context(Some(CharScopeContext::Completion));
26945        if trigger_in_words && classifier.is_word(char) {
26946            return true;
26947        }
26948
26949        buffer.completion_triggers().contains(text)
26950    }
26951
26952    fn show_snippets(&self) -> bool {
26953        true
26954    }
26955}
26956
26957impl SemanticsProvider for Entity<Project> {
26958    fn hover(
26959        &self,
26960        buffer: &Entity<Buffer>,
26961        position: text::Anchor,
26962        cx: &mut App,
26963    ) -> Option<Task<Option<Vec<project::Hover>>>> {
26964        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
26965    }
26966
26967    fn document_highlights(
26968        &self,
26969        buffer: &Entity<Buffer>,
26970        position: text::Anchor,
26971        cx: &mut App,
26972    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
26973        Some(self.update(cx, |project, cx| {
26974            project.document_highlights(buffer, position, cx)
26975        }))
26976    }
26977
26978    fn definitions(
26979        &self,
26980        buffer: &Entity<Buffer>,
26981        position: text::Anchor,
26982        kind: GotoDefinitionKind,
26983        cx: &mut App,
26984    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
26985        Some(self.update(cx, |project, cx| match kind {
26986            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
26987            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
26988            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
26989            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
26990        }))
26991    }
26992
26993    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
26994        self.update(cx, |project, cx| {
26995            if project
26996                .active_debug_session(cx)
26997                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
26998            {
26999                return true;
27000            }
27001
27002            buffer.update(cx, |buffer, cx| {
27003                project.any_language_server_supports_inlay_hints(buffer, cx)
27004            })
27005        })
27006    }
27007
27008    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27009        self.update(cx, |project, cx| {
27010            buffer.update(cx, |buffer, cx| {
27011                project.any_language_server_supports_semantic_tokens(buffer, cx)
27012            })
27013        })
27014    }
27015
27016    fn inline_values(
27017        &self,
27018        buffer_handle: Entity<Buffer>,
27019        range: Range<text::Anchor>,
27020        cx: &mut App,
27021    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27022        self.update(cx, |project, cx| {
27023            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27024
27025            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27026        })
27027    }
27028
27029    fn applicable_inlay_chunks(
27030        &self,
27031        buffer: &Entity<Buffer>,
27032        ranges: &[Range<text::Anchor>],
27033        cx: &mut App,
27034    ) -> Vec<Range<BufferRow>> {
27035        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
27036            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27037        })
27038    }
27039
27040    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27041        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
27042            lsp_store.invalidate_inlay_hints(for_buffers)
27043        });
27044    }
27045
27046    fn inlay_hints(
27047        &self,
27048        invalidate: InvalidationStrategy,
27049        buffer: Entity<Buffer>,
27050        ranges: Vec<Range<text::Anchor>>,
27051        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27052        cx: &mut App,
27053    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27054        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
27055            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27056        }))
27057    }
27058
27059    fn semantic_tokens(
27060        &self,
27061        buffer: Entity<Buffer>,
27062        refresh: Option<RefreshForServer>,
27063        cx: &mut App,
27064    ) -> Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>> {
27065        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
27066            lsp_store.semantic_tokens(buffer, refresh, cx)
27067        })
27068    }
27069
27070    fn range_for_rename(
27071        &self,
27072        buffer: &Entity<Buffer>,
27073        position: text::Anchor,
27074        cx: &mut App,
27075    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
27076        Some(self.update(cx, |project, cx| {
27077            let buffer = buffer.clone();
27078            let task = project.prepare_rename(buffer.clone(), position, cx);
27079            cx.spawn(async move |_, cx| {
27080                Ok(match task.await? {
27081                    PrepareRenameResponse::Success(range) => Some(range),
27082                    PrepareRenameResponse::InvalidPosition => None,
27083                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27084                        // Fallback on using TreeSitter info to determine identifier range
27085                        buffer.read_with(cx, |buffer, _| {
27086                            let snapshot = buffer.snapshot();
27087                            let (range, kind) = snapshot.surrounding_word(position, None);
27088                            if kind != Some(CharKind::Word) {
27089                                return None;
27090                            }
27091                            Some(
27092                                snapshot.anchor_before(range.start)
27093                                    ..snapshot.anchor_after(range.end),
27094                            )
27095                        })
27096                    }
27097                })
27098            })
27099        }))
27100    }
27101
27102    fn perform_rename(
27103        &self,
27104        buffer: &Entity<Buffer>,
27105        position: text::Anchor,
27106        new_name: String,
27107        cx: &mut App,
27108    ) -> Option<Task<Result<ProjectTransaction>>> {
27109        Some(self.update(cx, |project, cx| {
27110            project.perform_rename(buffer.clone(), position, new_name, cx)
27111        }))
27112    }
27113}
27114
27115fn consume_contiguous_rows(
27116    contiguous_row_selections: &mut Vec<Selection<Point>>,
27117    selection: &Selection<Point>,
27118    display_map: &DisplaySnapshot,
27119    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27120) -> (MultiBufferRow, MultiBufferRow) {
27121    contiguous_row_selections.push(selection.clone());
27122    let start_row = starting_row(selection, display_map);
27123    let mut end_row = ending_row(selection, display_map);
27124
27125    while let Some(next_selection) = selections.peek() {
27126        if next_selection.start.row <= end_row.0 {
27127            end_row = ending_row(next_selection, display_map);
27128            contiguous_row_selections.push(selections.next().unwrap().clone());
27129        } else {
27130            break;
27131        }
27132    }
27133    (start_row, end_row)
27134}
27135
27136fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27137    if selection.start.column > 0 {
27138        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27139    } else {
27140        MultiBufferRow(selection.start.row)
27141    }
27142}
27143
27144fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27145    if next_selection.end.column > 0 || next_selection.is_empty() {
27146        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27147    } else {
27148        MultiBufferRow(next_selection.end.row)
27149    }
27150}
27151
27152impl EditorSnapshot {
27153    pub fn remote_selections_in_range<'a>(
27154        &'a self,
27155        range: &'a Range<Anchor>,
27156        collaboration_hub: &dyn CollaborationHub,
27157        cx: &'a App,
27158    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27159        let participant_names = collaboration_hub.user_names(cx);
27160        let participant_indices = collaboration_hub.user_participant_indices(cx);
27161        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27162        let collaborators_by_replica_id = collaborators_by_peer_id
27163            .values()
27164            .map(|collaborator| (collaborator.replica_id, collaborator))
27165            .collect::<HashMap<_, _>>();
27166        self.buffer_snapshot()
27167            .selections_in_range(range, false)
27168            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27169                if replica_id == ReplicaId::AGENT {
27170                    Some(RemoteSelection {
27171                        replica_id,
27172                        selection,
27173                        cursor_shape,
27174                        line_mode,
27175                        collaborator_id: CollaboratorId::Agent,
27176                        user_name: Some("Agent".into()),
27177                        color: cx.theme().players().agent(),
27178                    })
27179                } else {
27180                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27181                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27182                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27183                    Some(RemoteSelection {
27184                        replica_id,
27185                        selection,
27186                        cursor_shape,
27187                        line_mode,
27188                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27189                        user_name,
27190                        color: if let Some(index) = participant_index {
27191                            cx.theme().players().color_for_participant(index.0)
27192                        } else {
27193                            cx.theme().players().absent()
27194                        },
27195                    })
27196                }
27197            })
27198    }
27199
27200    pub fn hunks_for_ranges(
27201        &self,
27202        ranges: impl IntoIterator<Item = Range<Point>>,
27203    ) -> Vec<MultiBufferDiffHunk> {
27204        let mut hunks = Vec::new();
27205        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27206            HashMap::default();
27207        for query_range in ranges {
27208            let query_rows =
27209                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27210            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27211                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27212            ) {
27213                // Include deleted hunks that are adjacent to the query range, because
27214                // otherwise they would be missed.
27215                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27216                if hunk.status().is_deleted() {
27217                    intersects_range |= hunk.row_range.start == query_rows.end;
27218                    intersects_range |= hunk.row_range.end == query_rows.start;
27219                }
27220                if intersects_range {
27221                    if !processed_buffer_rows
27222                        .entry(hunk.buffer_id)
27223                        .or_default()
27224                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27225                    {
27226                        continue;
27227                    }
27228                    hunks.push(hunk);
27229                }
27230            }
27231        }
27232
27233        hunks
27234    }
27235
27236    fn display_diff_hunks_for_rows<'a>(
27237        &'a self,
27238        display_rows: Range<DisplayRow>,
27239        folded_buffers: &'a HashSet<BufferId>,
27240    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
27241        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
27242        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
27243
27244        self.buffer_snapshot()
27245            .diff_hunks_in_range(buffer_start..buffer_end)
27246            .filter_map(|hunk| {
27247                if folded_buffers.contains(&hunk.buffer_id)
27248                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
27249                {
27250                    return None;
27251                }
27252
27253                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
27254                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
27255                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
27256                    let line_len = self.buffer_snapshot().line_len(last_row);
27257                    Point::new(last_row.0, line_len)
27258                } else {
27259                    Point::new(hunk.row_range.end.0, 0)
27260                };
27261
27262                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
27263                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
27264
27265                let display_hunk = if hunk_display_start.column() != 0 {
27266                    DisplayDiffHunk::Folded {
27267                        display_row: hunk_display_start.row(),
27268                    }
27269                } else {
27270                    let mut end_row = hunk_display_end.row();
27271                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
27272                        end_row.0 += 1;
27273                    }
27274                    let is_created_file = hunk.is_created_file();
27275
27276                    DisplayDiffHunk::Unfolded {
27277                        status: hunk.status(),
27278                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
27279                            ..hunk.diff_base_byte_range.end.0,
27280                        word_diffs: hunk.word_diffs,
27281                        display_row_range: hunk_display_start.row()..end_row,
27282                        multi_buffer_range: Anchor::range_in_buffer(
27283                            hunk.excerpt_id,
27284                            hunk.buffer_range,
27285                        ),
27286                        is_created_file,
27287                    }
27288                };
27289
27290                Some(display_hunk)
27291            })
27292    }
27293
27294    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
27295        self.display_snapshot
27296            .buffer_snapshot()
27297            .language_at(position)
27298    }
27299
27300    pub fn is_focused(&self) -> bool {
27301        self.is_focused
27302    }
27303
27304    pub fn placeholder_text(&self) -> Option<String> {
27305        self.placeholder_display_snapshot
27306            .as_ref()
27307            .map(|display_map| display_map.text())
27308    }
27309
27310    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
27311        self.scroll_anchor.scroll_position(&self.display_snapshot)
27312    }
27313
27314    pub fn gutter_dimensions(
27315        &self,
27316        font_id: FontId,
27317        font_size: Pixels,
27318        style: &EditorStyle,
27319        window: &mut Window,
27320        cx: &App,
27321    ) -> GutterDimensions {
27322        if self.show_gutter
27323            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27324            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27325        {
27326            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27327                matches!(
27328                    ProjectSettings::get_global(cx).git.git_gutter,
27329                    GitGutterSetting::TrackedFiles
27330                )
27331            });
27332            let gutter_settings = EditorSettings::get_global(cx).gutter;
27333            let show_line_numbers = self
27334                .show_line_numbers
27335                .unwrap_or(gutter_settings.line_numbers);
27336            let line_gutter_width = if show_line_numbers {
27337                // Avoid flicker-like gutter resizes when the line number gains another digit by
27338                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27339                let min_width_for_number_on_gutter =
27340                    ch_advance * gutter_settings.min_line_number_digits as f32;
27341                self.max_line_number_width(style, window)
27342                    .max(min_width_for_number_on_gutter)
27343            } else {
27344                0.0.into()
27345            };
27346
27347            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27348            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27349
27350            let git_blame_entries_width =
27351                self.git_blame_gutter_max_author_length
27352                    .map(|max_author_length| {
27353                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27354                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27355
27356                        /// The number of characters to dedicate to gaps and margins.
27357                        const SPACING_WIDTH: usize = 4;
27358
27359                        let max_char_count = max_author_length.min(renderer.max_author_length())
27360                            + ::git::SHORT_SHA_LENGTH
27361                            + MAX_RELATIVE_TIMESTAMP.len()
27362                            + SPACING_WIDTH;
27363
27364                        ch_advance * max_char_count
27365                    });
27366
27367            let is_singleton = self.buffer_snapshot().is_singleton();
27368
27369            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27370            left_padding += if !is_singleton {
27371                ch_width * 4.0
27372            } else if show_runnables || show_breakpoints {
27373                ch_width * 3.0
27374            } else if show_git_gutter && show_line_numbers {
27375                ch_width * 2.0
27376            } else if show_git_gutter || show_line_numbers {
27377                ch_width
27378            } else {
27379                px(0.)
27380            };
27381
27382            let shows_folds = is_singleton && gutter_settings.folds;
27383
27384            let right_padding = if shows_folds && show_line_numbers {
27385                ch_width * 4.0
27386            } else if shows_folds || (!is_singleton && show_line_numbers) {
27387                ch_width * 3.0
27388            } else if show_line_numbers {
27389                ch_width
27390            } else {
27391                px(0.)
27392            };
27393
27394            GutterDimensions {
27395                left_padding,
27396                right_padding,
27397                width: line_gutter_width + left_padding + right_padding,
27398                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27399                git_blame_entries_width,
27400            }
27401        } else if self.offset_content {
27402            GutterDimensions::default_with_margin(font_id, font_size, cx)
27403        } else {
27404            GutterDimensions::default()
27405        }
27406    }
27407
27408    pub fn render_crease_toggle(
27409        &self,
27410        buffer_row: MultiBufferRow,
27411        row_contains_cursor: bool,
27412        editor: Entity<Editor>,
27413        window: &mut Window,
27414        cx: &mut App,
27415    ) -> Option<AnyElement> {
27416        let folded = self.is_line_folded(buffer_row);
27417        let mut is_foldable = false;
27418
27419        if let Some(crease) = self
27420            .crease_snapshot
27421            .query_row(buffer_row, self.buffer_snapshot())
27422        {
27423            is_foldable = true;
27424            match crease {
27425                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27426                    if let Some(render_toggle) = render_toggle {
27427                        let toggle_callback =
27428                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27429                                if folded {
27430                                    editor.update(cx, |editor, cx| {
27431                                        editor.fold_at(buffer_row, window, cx)
27432                                    });
27433                                } else {
27434                                    editor.update(cx, |editor, cx| {
27435                                        editor.unfold_at(buffer_row, window, cx)
27436                                    });
27437                                }
27438                            });
27439                        return Some((render_toggle)(
27440                            buffer_row,
27441                            folded,
27442                            toggle_callback,
27443                            window,
27444                            cx,
27445                        ));
27446                    }
27447                }
27448            }
27449        }
27450
27451        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
27452
27453        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
27454            Some(
27455                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
27456                    .toggle_state(folded)
27457                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
27458                        if folded {
27459                            this.unfold_at(buffer_row, window, cx);
27460                        } else {
27461                            this.fold_at(buffer_row, window, cx);
27462                        }
27463                    }))
27464                    .into_any_element(),
27465            )
27466        } else {
27467            None
27468        }
27469    }
27470
27471    pub fn render_crease_trailer(
27472        &self,
27473        buffer_row: MultiBufferRow,
27474        window: &mut Window,
27475        cx: &mut App,
27476    ) -> Option<AnyElement> {
27477        let folded = self.is_line_folded(buffer_row);
27478        if let Crease::Inline { render_trailer, .. } = self
27479            .crease_snapshot
27480            .query_row(buffer_row, self.buffer_snapshot())?
27481        {
27482            let render_trailer = render_trailer.as_ref()?;
27483            Some(render_trailer(buffer_row, folded, window, cx))
27484        } else {
27485            None
27486        }
27487    }
27488
27489    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
27490        let digit_count = self.widest_line_number().ilog10() + 1;
27491        column_pixels(style, digit_count as usize, window)
27492    }
27493
27494    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
27495    ///
27496    /// This is positive if `base` is before `line`.
27497    fn relative_line_delta(
27498        &self,
27499        current_selection_head: DisplayRow,
27500        first_visible_row: DisplayRow,
27501        consider_wrapped_lines: bool,
27502    ) -> i64 {
27503        let current_selection_head = current_selection_head.as_display_point().to_point(self);
27504        let first_visible_row = first_visible_row.as_display_point().to_point(self);
27505
27506        if consider_wrapped_lines {
27507            let wrap_snapshot = self.wrap_snapshot();
27508            let base_wrap_row = wrap_snapshot
27509                .make_wrap_point(current_selection_head, Bias::Left)
27510                .row();
27511            let wrap_row = wrap_snapshot
27512                .make_wrap_point(first_visible_row, Bias::Left)
27513                .row();
27514
27515            wrap_row.0 as i64 - base_wrap_row.0 as i64
27516        } else {
27517            let fold_snapshot = self.fold_snapshot();
27518            let base_fold_row = fold_snapshot
27519                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
27520                .row();
27521            let fold_row = fold_snapshot
27522                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
27523                .row();
27524
27525            fold_row as i64 - base_fold_row as i64
27526        }
27527    }
27528
27529    /// Returns the unsigned relative line number to display for each row in `rows`.
27530    ///
27531    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
27532    pub fn calculate_relative_line_numbers(
27533        &self,
27534        rows: &Range<DisplayRow>,
27535        current_selection_head: DisplayRow,
27536        count_wrapped_lines: bool,
27537    ) -> HashMap<DisplayRow, u32> {
27538        let initial_offset =
27539            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
27540        let current_selection_point = current_selection_head.as_display_point().to_point(self);
27541
27542        self.row_infos(rows.start)
27543            .take(rows.len())
27544            .enumerate()
27545            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
27546            .filter(|(_row, row_info)| {
27547                row_info.buffer_row.is_some()
27548                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
27549            })
27550            .enumerate()
27551            .filter(|(_, (row, row_info))| {
27552                // We want to check here that
27553                // - the row is not the current selection head to ensure the current
27554                // line has absolute numbering
27555                // - similarly, should the selection head live in a soft-wrapped line
27556                // and we are not counting those, that the parent line keeps its
27557                // absolute number
27558                // - lastly, if we are in a deleted line, it is fine to number this
27559                // relative with 0, as otherwise it would have no line number at all
27560                (*row != current_selection_head
27561                    && (count_wrapped_lines
27562                        || row_info.buffer_row != Some(current_selection_point.row)))
27563                    || row_info
27564                        .diff_status
27565                        .is_some_and(|status| status.is_deleted())
27566            })
27567            .map(|(i, (row, _))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
27568            .collect()
27569    }
27570}
27571
27572pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
27573    let font_size = style.text.font_size.to_pixels(window.rem_size());
27574    let layout = window.text_system().shape_line(
27575        SharedString::from(" ".repeat(column)),
27576        font_size,
27577        &[TextRun {
27578            len: column,
27579            font: style.text.font(),
27580            color: Hsla::default(),
27581            ..Default::default()
27582        }],
27583        None,
27584    );
27585
27586    layout.width
27587}
27588
27589impl Deref for EditorSnapshot {
27590    type Target = DisplaySnapshot;
27591
27592    fn deref(&self) -> &Self::Target {
27593        &self.display_snapshot
27594    }
27595}
27596
27597#[derive(Clone, Debug, PartialEq, Eq)]
27598pub enum EditorEvent {
27599    /// Emitted when the stored review comments change (added, removed, or updated).
27600    ReviewCommentsChanged {
27601        /// The new total count of review comments.
27602        total_count: usize,
27603    },
27604    InputIgnored {
27605        text: Arc<str>,
27606    },
27607    InputHandled {
27608        utf16_range_to_replace: Option<Range<isize>>,
27609        text: Arc<str>,
27610    },
27611    ExcerptsAdded {
27612        buffer: Entity<Buffer>,
27613        predecessor: ExcerptId,
27614        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
27615    },
27616    ExcerptsRemoved {
27617        ids: Vec<ExcerptId>,
27618        removed_buffer_ids: Vec<BufferId>,
27619    },
27620    BufferFoldToggled {
27621        ids: Vec<ExcerptId>,
27622        folded: bool,
27623    },
27624    ExcerptsEdited {
27625        ids: Vec<ExcerptId>,
27626    },
27627    ExcerptsExpanded {
27628        ids: Vec<ExcerptId>,
27629    },
27630    ExpandExcerptsRequested {
27631        excerpt_ids: Vec<ExcerptId>,
27632        lines: u32,
27633        direction: ExpandExcerptDirection,
27634    },
27635    StageOrUnstageRequested {
27636        stage: bool,
27637        hunks: Vec<MultiBufferDiffHunk>,
27638    },
27639    OpenExcerptsRequested {
27640        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
27641        split: bool,
27642    },
27643    RestoreRequested {
27644        hunks: Vec<MultiBufferDiffHunk>,
27645    },
27646    BufferEdited,
27647    Edited {
27648        transaction_id: clock::Lamport,
27649    },
27650    Reparsed(BufferId),
27651    Focused,
27652    FocusedIn,
27653    Blurred,
27654    DirtyChanged,
27655    Saved,
27656    TitleChanged,
27657    SelectionsChanged {
27658        local: bool,
27659    },
27660    ScrollPositionChanged {
27661        local: bool,
27662        autoscroll: bool,
27663    },
27664    TransactionUndone {
27665        transaction_id: clock::Lamport,
27666    },
27667    TransactionBegun {
27668        transaction_id: clock::Lamport,
27669    },
27670    CursorShapeChanged,
27671    BreadcrumbsChanged,
27672    PushedToNavHistory {
27673        anchor: Anchor,
27674        is_deactivate: bool,
27675    },
27676}
27677
27678impl EventEmitter<EditorEvent> for Editor {}
27679
27680impl Focusable for Editor {
27681    fn focus_handle(&self, _cx: &App) -> FocusHandle {
27682        self.focus_handle.clone()
27683    }
27684}
27685
27686impl Render for Editor {
27687    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
27688        EditorElement::new(&cx.entity(), self.create_style(cx))
27689    }
27690}
27691
27692impl EntityInputHandler for Editor {
27693    fn text_for_range(
27694        &mut self,
27695        range_utf16: Range<usize>,
27696        adjusted_range: &mut Option<Range<usize>>,
27697        _: &mut Window,
27698        cx: &mut Context<Self>,
27699    ) -> Option<String> {
27700        let snapshot = self.buffer.read(cx).read(cx);
27701        let start = snapshot.clip_offset_utf16(
27702            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
27703            Bias::Left,
27704        );
27705        let end = snapshot.clip_offset_utf16(
27706            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
27707            Bias::Right,
27708        );
27709        if (start.0.0..end.0.0) != range_utf16 {
27710            adjusted_range.replace(start.0.0..end.0.0);
27711        }
27712        Some(snapshot.text_for_range(start..end).collect())
27713    }
27714
27715    fn selected_text_range(
27716        &mut self,
27717        ignore_disabled_input: bool,
27718        _: &mut Window,
27719        cx: &mut Context<Self>,
27720    ) -> Option<UTF16Selection> {
27721        // Prevent the IME menu from appearing when holding down an alphabetic key
27722        // while input is disabled.
27723        if !ignore_disabled_input && !self.input_enabled {
27724            return None;
27725        }
27726
27727        let selection = self
27728            .selections
27729            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
27730        let range = selection.range();
27731
27732        Some(UTF16Selection {
27733            range: range.start.0.0..range.end.0.0,
27734            reversed: selection.reversed,
27735        })
27736    }
27737
27738    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
27739        let snapshot = self.buffer.read(cx).read(cx);
27740        let range = self
27741            .text_highlights(HighlightKey::InputComposition, cx)?
27742            .1
27743            .first()?;
27744        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
27745    }
27746
27747    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
27748        self.clear_highlights(HighlightKey::InputComposition, cx);
27749        self.ime_transaction.take();
27750    }
27751
27752    fn replace_text_in_range(
27753        &mut self,
27754        range_utf16: Option<Range<usize>>,
27755        text: &str,
27756        window: &mut Window,
27757        cx: &mut Context<Self>,
27758    ) {
27759        if !self.input_enabled {
27760            cx.emit(EditorEvent::InputIgnored { text: text.into() });
27761            return;
27762        }
27763
27764        self.transact(window, cx, |this, window, cx| {
27765            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
27766                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27767                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27768                Some(this.selection_replacement_ranges(range_utf16, cx))
27769            } else {
27770                this.marked_text_ranges(cx)
27771            };
27772
27773            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
27774                let newest_selection_id = this.selections.newest_anchor().id;
27775                this.selections
27776                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27777                    .iter()
27778                    .zip(ranges_to_replace.iter())
27779                    .find_map(|(selection, range)| {
27780                        if selection.id == newest_selection_id {
27781                            Some(
27782                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27783                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27784                            )
27785                        } else {
27786                            None
27787                        }
27788                    })
27789            });
27790
27791            cx.emit(EditorEvent::InputHandled {
27792                utf16_range_to_replace: range_to_replace,
27793                text: text.into(),
27794            });
27795
27796            if let Some(new_selected_ranges) = new_selected_ranges {
27797                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27798                    selections.select_ranges(new_selected_ranges)
27799                });
27800                this.backspace(&Default::default(), window, cx);
27801            }
27802
27803            this.handle_input(text, window, cx);
27804        });
27805
27806        if let Some(transaction) = self.ime_transaction {
27807            self.buffer.update(cx, |buffer, cx| {
27808                buffer.group_until_transaction(transaction, cx);
27809            });
27810        }
27811
27812        self.unmark_text(window, cx);
27813    }
27814
27815    fn replace_and_mark_text_in_range(
27816        &mut self,
27817        range_utf16: Option<Range<usize>>,
27818        text: &str,
27819        new_selected_range_utf16: Option<Range<usize>>,
27820        window: &mut Window,
27821        cx: &mut Context<Self>,
27822    ) {
27823        if !self.input_enabled {
27824            return;
27825        }
27826
27827        let transaction = self.transact(window, cx, |this, window, cx| {
27828            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
27829                let snapshot = this.buffer.read(cx).read(cx);
27830                if let Some(relative_range_utf16) = range_utf16.as_ref() {
27831                    for marked_range in &mut marked_ranges {
27832                        marked_range.end = marked_range.start + relative_range_utf16.end;
27833                        marked_range.start += relative_range_utf16.start;
27834                        marked_range.start =
27835                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
27836                        marked_range.end =
27837                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
27838                    }
27839                }
27840                Some(marked_ranges)
27841            } else if let Some(range_utf16) = range_utf16 {
27842                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27843                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27844                Some(this.selection_replacement_ranges(range_utf16, cx))
27845            } else {
27846                None
27847            };
27848
27849            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
27850                let newest_selection_id = this.selections.newest_anchor().id;
27851                this.selections
27852                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27853                    .iter()
27854                    .zip(ranges_to_replace.iter())
27855                    .find_map(|(selection, range)| {
27856                        if selection.id == newest_selection_id {
27857                            Some(
27858                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27859                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27860                            )
27861                        } else {
27862                            None
27863                        }
27864                    })
27865            });
27866
27867            cx.emit(EditorEvent::InputHandled {
27868                utf16_range_to_replace: range_to_replace,
27869                text: text.into(),
27870            });
27871
27872            if let Some(ranges) = ranges_to_replace {
27873                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
27874                    s.select_ranges(ranges)
27875                });
27876            }
27877
27878            let marked_ranges = {
27879                let snapshot = this.buffer.read(cx).read(cx);
27880                this.selections
27881                    .disjoint_anchors_arc()
27882                    .iter()
27883                    .map(|selection| {
27884                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
27885                    })
27886                    .collect::<Vec<_>>()
27887            };
27888
27889            if text.is_empty() {
27890                this.unmark_text(window, cx);
27891            } else {
27892                this.highlight_text(
27893                    HighlightKey::InputComposition,
27894                    marked_ranges.clone(),
27895                    HighlightStyle {
27896                        underline: Some(UnderlineStyle {
27897                            thickness: px(1.),
27898                            color: None,
27899                            wavy: false,
27900                        }),
27901                        ..Default::default()
27902                    },
27903                    cx,
27904                );
27905            }
27906
27907            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
27908            let use_autoclose = this.use_autoclose;
27909            let use_auto_surround = this.use_auto_surround;
27910            this.set_use_autoclose(false);
27911            this.set_use_auto_surround(false);
27912            this.handle_input(text, window, cx);
27913            this.set_use_autoclose(use_autoclose);
27914            this.set_use_auto_surround(use_auto_surround);
27915
27916            if let Some(new_selected_range) = new_selected_range_utf16 {
27917                let snapshot = this.buffer.read(cx).read(cx);
27918                let new_selected_ranges = marked_ranges
27919                    .into_iter()
27920                    .map(|marked_range| {
27921                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
27922                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
27923                            insertion_start.0 + new_selected_range.start,
27924                        ));
27925                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
27926                            insertion_start.0 + new_selected_range.end,
27927                        ));
27928                        snapshot.clip_offset_utf16(new_start, Bias::Left)
27929                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
27930                    })
27931                    .collect::<Vec<_>>();
27932
27933                drop(snapshot);
27934                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27935                    selections.select_ranges(new_selected_ranges)
27936                });
27937            }
27938        });
27939
27940        self.ime_transaction = self.ime_transaction.or(transaction);
27941        if let Some(transaction) = self.ime_transaction {
27942            self.buffer.update(cx, |buffer, cx| {
27943                buffer.group_until_transaction(transaction, cx);
27944            });
27945        }
27946
27947        if self
27948            .text_highlights(HighlightKey::InputComposition, cx)
27949            .is_none()
27950        {
27951            self.ime_transaction.take();
27952        }
27953    }
27954
27955    fn bounds_for_range(
27956        &mut self,
27957        range_utf16: Range<usize>,
27958        element_bounds: gpui::Bounds<Pixels>,
27959        window: &mut Window,
27960        cx: &mut Context<Self>,
27961    ) -> Option<gpui::Bounds<Pixels>> {
27962        let text_layout_details = self.text_layout_details(window, cx);
27963        let CharacterDimensions {
27964            em_width,
27965            em_advance,
27966            line_height,
27967        } = self.character_dimensions(window, cx);
27968
27969        let snapshot = self.snapshot(window, cx);
27970        let scroll_position = snapshot.scroll_position();
27971        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
27972
27973        let start =
27974            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
27975        let x = Pixels::from(
27976            ScrollOffset::from(
27977                snapshot.x_for_display_point(start, &text_layout_details)
27978                    + self.gutter_dimensions.full_width(),
27979            ) - scroll_left,
27980        );
27981        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
27982
27983        Some(Bounds {
27984            origin: element_bounds.origin + point(x, y),
27985            size: size(em_width, line_height),
27986        })
27987    }
27988
27989    fn character_index_for_point(
27990        &mut self,
27991        point: gpui::Point<Pixels>,
27992        _window: &mut Window,
27993        _cx: &mut Context<Self>,
27994    ) -> Option<usize> {
27995        let position_map = self.last_position_map.as_ref()?;
27996        if !position_map.text_hitbox.contains(&point) {
27997            return None;
27998        }
27999        let display_point = position_map.point_for_position(point).previous_valid;
28000        let anchor = position_map
28001            .snapshot
28002            .display_point_to_anchor(display_point, Bias::Left);
28003        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28004        Some(utf16_offset.0.0)
28005    }
28006
28007    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28008        self.input_enabled
28009    }
28010}
28011
28012trait SelectionExt {
28013    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28014    fn spanned_rows(
28015        &self,
28016        include_end_if_at_line_start: bool,
28017        map: &DisplaySnapshot,
28018    ) -> Range<MultiBufferRow>;
28019}
28020
28021impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28022    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28023        let start = self
28024            .start
28025            .to_point(map.buffer_snapshot())
28026            .to_display_point(map);
28027        let end = self
28028            .end
28029            .to_point(map.buffer_snapshot())
28030            .to_display_point(map);
28031        if self.reversed {
28032            end..start
28033        } else {
28034            start..end
28035        }
28036    }
28037
28038    fn spanned_rows(
28039        &self,
28040        include_end_if_at_line_start: bool,
28041        map: &DisplaySnapshot,
28042    ) -> Range<MultiBufferRow> {
28043        let start = self.start.to_point(map.buffer_snapshot());
28044        let mut end = self.end.to_point(map.buffer_snapshot());
28045        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28046            end.row -= 1;
28047        }
28048
28049        let buffer_start = map.prev_line_boundary(start).0;
28050        let buffer_end = map.next_line_boundary(end).0;
28051        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28052    }
28053}
28054
28055impl<T: InvalidationRegion> InvalidationStack<T> {
28056    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28057    where
28058        S: Clone + ToOffset,
28059    {
28060        while let Some(region) = self.last() {
28061            let all_selections_inside_invalidation_ranges =
28062                if selections.len() == region.ranges().len() {
28063                    selections
28064                        .iter()
28065                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28066                        .all(|(selection, invalidation_range)| {
28067                            let head = selection.head().to_offset(buffer);
28068                            invalidation_range.start <= head && invalidation_range.end >= head
28069                        })
28070                } else {
28071                    false
28072                };
28073
28074            if all_selections_inside_invalidation_ranges {
28075                break;
28076            } else {
28077                self.pop();
28078            }
28079        }
28080    }
28081}
28082
28083#[derive(Clone)]
28084struct ErasedEditorImpl(Entity<Editor>);
28085
28086impl ui_input::ErasedEditor for ErasedEditorImpl {
28087    fn text(&self, cx: &App) -> String {
28088        self.0.read(cx).text(cx)
28089    }
28090
28091    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28092        self.0.update(cx, |this, cx| {
28093            this.set_text(text, window, cx);
28094        })
28095    }
28096
28097    fn clear(&self, window: &mut Window, cx: &mut App) {
28098        self.0.update(cx, |this, cx| this.clear(window, cx));
28099    }
28100
28101    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28102        self.0.update(cx, |this, cx| {
28103            this.set_placeholder_text(text, window, cx);
28104        });
28105    }
28106
28107    fn focus_handle(&self, cx: &App) -> FocusHandle {
28108        self.0.read(cx).focus_handle(cx)
28109    }
28110
28111    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28112        let settings = ThemeSettings::get_global(cx);
28113        let theme_color = cx.theme().colors();
28114
28115        let text_style = TextStyle {
28116            font_family: settings.ui_font.family.clone(),
28117            font_features: settings.ui_font.features.clone(),
28118            font_size: rems(0.875).into(),
28119            font_weight: settings.buffer_font.weight,
28120            font_style: FontStyle::Normal,
28121            line_height: relative(1.2),
28122            color: theme_color.text,
28123            ..Default::default()
28124        };
28125        let editor_style = EditorStyle {
28126            background: theme_color.ghost_element_background,
28127            local_player: cx.theme().players().local(),
28128            syntax: cx.theme().syntax().clone(),
28129            text: text_style,
28130            ..Default::default()
28131        };
28132        EditorElement::new(&self.0, editor_style).into_any()
28133    }
28134
28135    fn as_any(&self) -> &dyn Any {
28136        &self.0
28137    }
28138
28139    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28140        self.0.update(cx, |editor, cx| {
28141            let editor_offset = editor.buffer().read(cx).len(cx);
28142            editor.change_selections(
28143                SelectionEffects::scroll(Autoscroll::Next),
28144                window,
28145                cx,
28146                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28147            );
28148        });
28149    }
28150
28151    fn subscribe(
28152        &self,
28153        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28154        window: &mut Window,
28155        cx: &mut App,
28156    ) -> Subscription {
28157        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28158            let event = match event {
28159                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28160                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28161                _ => return,
28162            };
28163            (callback)(event, window, cx);
28164        })
28165    }
28166
28167    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28168        self.0.update(cx, |editor, cx| {
28169            editor.set_masked(masked, cx);
28170        });
28171    }
28172}
28173impl<T> Default for InvalidationStack<T> {
28174    fn default() -> Self {
28175        Self(Default::default())
28176    }
28177}
28178
28179impl<T> Deref for InvalidationStack<T> {
28180    type Target = Vec<T>;
28181
28182    fn deref(&self) -> &Self::Target {
28183        &self.0
28184    }
28185}
28186
28187impl<T> DerefMut for InvalidationStack<T> {
28188    fn deref_mut(&mut self) -> &mut Self::Target {
28189        &mut self.0
28190    }
28191}
28192
28193impl InvalidationRegion for SnippetState {
28194    fn ranges(&self) -> &[Range<Anchor>] {
28195        &self.ranges[self.active_index]
28196    }
28197}
28198
28199fn edit_prediction_edit_text(
28200    current_snapshot: &BufferSnapshot,
28201    edits: &[(Range<Anchor>, impl AsRef<str>)],
28202    edit_preview: &EditPreview,
28203    include_deletions: bool,
28204    cx: &App,
28205) -> HighlightedText {
28206    let edits = edits
28207        .iter()
28208        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
28209        .collect::<Vec<_>>();
28210
28211    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
28212}
28213
28214fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
28215    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
28216    // Just show the raw edit text with basic styling
28217    let mut text = String::new();
28218    let mut highlights = Vec::new();
28219
28220    let insertion_highlight_style = HighlightStyle {
28221        color: Some(cx.theme().colors().text),
28222        ..Default::default()
28223    };
28224
28225    for (_, edit_text) in edits {
28226        let start_offset = text.len();
28227        text.push_str(edit_text);
28228        let end_offset = text.len();
28229
28230        if start_offset < end_offset {
28231            highlights.push((start_offset..end_offset, insertion_highlight_style));
28232        }
28233    }
28234
28235    HighlightedText {
28236        text: text.into(),
28237        highlights,
28238    }
28239}
28240
28241pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
28242    match severity {
28243        lsp::DiagnosticSeverity::ERROR => colors.error,
28244        lsp::DiagnosticSeverity::WARNING => colors.warning,
28245        lsp::DiagnosticSeverity::INFORMATION => colors.info,
28246        lsp::DiagnosticSeverity::HINT => colors.info,
28247        _ => colors.ignored,
28248    }
28249}
28250
28251pub fn styled_runs_for_code_label<'a>(
28252    label: &'a CodeLabel,
28253    syntax_theme: &'a theme::SyntaxTheme,
28254    local_player: &'a theme::PlayerColor,
28255) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
28256    let fade_out = HighlightStyle {
28257        fade_out: Some(0.35),
28258        ..Default::default()
28259    };
28260
28261    let mut prev_end = label.filter_range.end;
28262    label
28263        .runs
28264        .iter()
28265        .enumerate()
28266        .flat_map(move |(ix, (range, highlight_id))| {
28267            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
28268                HighlightStyle {
28269                    color: Some(local_player.cursor),
28270                    ..Default::default()
28271                }
28272            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
28273                HighlightStyle {
28274                    background_color: Some(local_player.selection),
28275                    ..Default::default()
28276                }
28277            } else if let Some(style) = highlight_id.style(syntax_theme) {
28278                style
28279            } else {
28280                return Default::default();
28281            };
28282            let muted_style = style.highlight(fade_out);
28283
28284            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
28285            if range.start >= label.filter_range.end {
28286                if range.start > prev_end {
28287                    runs.push((prev_end..range.start, fade_out));
28288                }
28289                runs.push((range.clone(), muted_style));
28290            } else if range.end <= label.filter_range.end {
28291                runs.push((range.clone(), style));
28292            } else {
28293                runs.push((range.start..label.filter_range.end, style));
28294                runs.push((label.filter_range.end..range.end, muted_style));
28295            }
28296            prev_end = cmp::max(prev_end, range.end);
28297
28298            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
28299                runs.push((prev_end..label.text.len(), fade_out));
28300            }
28301
28302            runs
28303        })
28304}
28305
28306pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
28307    let mut prev_index = 0;
28308    let mut prev_codepoint: Option<char> = None;
28309    text.char_indices()
28310        .chain([(text.len(), '\0')])
28311        .filter_map(move |(index, codepoint)| {
28312            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28313            let is_boundary = index == text.len()
28314                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
28315                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
28316            if is_boundary {
28317                let chunk = &text[prev_index..index];
28318                prev_index = index;
28319                Some(chunk)
28320            } else {
28321                None
28322            }
28323        })
28324}
28325
28326/// Given a string of text immediately before the cursor, iterates over possible
28327/// strings a snippet could match to. More precisely: returns an iterator over
28328/// suffixes of `text` created by splitting at word boundaries (before & after
28329/// every non-word character).
28330///
28331/// Shorter suffixes are returned first.
28332pub(crate) fn snippet_candidate_suffixes(
28333    text: &str,
28334    is_word_char: impl Fn(char) -> bool,
28335) -> impl std::iter::Iterator<Item = &str> {
28336    let mut prev_index = text.len();
28337    let mut prev_codepoint = None;
28338    text.char_indices()
28339        .rev()
28340        .chain([(0, '\0')])
28341        .filter_map(move |(index, codepoint)| {
28342            let prev_index = std::mem::replace(&mut prev_index, index);
28343            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28344            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28345                None
28346            } else {
28347                let chunk = &text[prev_index..]; // go to end of string
28348                Some(chunk)
28349            }
28350        })
28351}
28352
28353pub trait RangeToAnchorExt: Sized {
28354    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28355
28356    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28357        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28358        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28359    }
28360}
28361
28362impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28363    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28364        let start_offset = self.start.to_offset(snapshot);
28365        let end_offset = self.end.to_offset(snapshot);
28366        if start_offset == end_offset {
28367            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28368        } else {
28369            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28370        }
28371    }
28372}
28373
28374pub trait RowExt {
28375    fn as_f64(&self) -> f64;
28376
28377    fn next_row(&self) -> Self;
28378
28379    fn previous_row(&self) -> Self;
28380
28381    fn minus(&self, other: Self) -> u32;
28382}
28383
28384impl RowExt for DisplayRow {
28385    fn as_f64(&self) -> f64 {
28386        self.0 as _
28387    }
28388
28389    fn next_row(&self) -> Self {
28390        Self(self.0 + 1)
28391    }
28392
28393    fn previous_row(&self) -> Self {
28394        Self(self.0.saturating_sub(1))
28395    }
28396
28397    fn minus(&self, other: Self) -> u32 {
28398        self.0 - other.0
28399    }
28400}
28401
28402impl RowExt for MultiBufferRow {
28403    fn as_f64(&self) -> f64 {
28404        self.0 as _
28405    }
28406
28407    fn next_row(&self) -> Self {
28408        Self(self.0 + 1)
28409    }
28410
28411    fn previous_row(&self) -> Self {
28412        Self(self.0.saturating_sub(1))
28413    }
28414
28415    fn minus(&self, other: Self) -> u32 {
28416        self.0 - other.0
28417    }
28418}
28419
28420trait RowRangeExt {
28421    type Row;
28422
28423    fn len(&self) -> usize;
28424
28425    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
28426}
28427
28428impl RowRangeExt for Range<MultiBufferRow> {
28429    type Row = MultiBufferRow;
28430
28431    fn len(&self) -> usize {
28432        (self.end.0 - self.start.0) as usize
28433    }
28434
28435    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
28436        (self.start.0..self.end.0).map(MultiBufferRow)
28437    }
28438}
28439
28440impl RowRangeExt for Range<DisplayRow> {
28441    type Row = DisplayRow;
28442
28443    fn len(&self) -> usize {
28444        (self.end.0 - self.start.0) as usize
28445    }
28446
28447    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
28448        (self.start.0..self.end.0).map(DisplayRow)
28449    }
28450}
28451
28452/// If select range has more than one line, we
28453/// just point the cursor to range.start.
28454fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
28455    if range.start.row == range.end.row {
28456        range
28457    } else {
28458        range.start..range.start
28459    }
28460}
28461pub struct KillRing(ClipboardItem);
28462impl Global for KillRing {}
28463
28464const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
28465
28466enum BreakpointPromptEditAction {
28467    Log,
28468    Condition,
28469    HitCondition,
28470}
28471
28472struct BreakpointPromptEditor {
28473    pub(crate) prompt: Entity<Editor>,
28474    editor: WeakEntity<Editor>,
28475    breakpoint_anchor: Anchor,
28476    breakpoint: Breakpoint,
28477    edit_action: BreakpointPromptEditAction,
28478    block_ids: HashSet<CustomBlockId>,
28479    editor_margins: Arc<Mutex<EditorMargins>>,
28480    _subscriptions: Vec<Subscription>,
28481}
28482
28483impl BreakpointPromptEditor {
28484    const MAX_LINES: u8 = 4;
28485
28486    fn new(
28487        editor: WeakEntity<Editor>,
28488        breakpoint_anchor: Anchor,
28489        breakpoint: Breakpoint,
28490        edit_action: BreakpointPromptEditAction,
28491        window: &mut Window,
28492        cx: &mut Context<Self>,
28493    ) -> Self {
28494        let base_text = match edit_action {
28495            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
28496            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
28497            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
28498        }
28499        .map(|msg| msg.to_string())
28500        .unwrap_or_default();
28501
28502        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
28503        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
28504
28505        let prompt = cx.new(|cx| {
28506            let mut prompt = Editor::new(
28507                EditorMode::AutoHeight {
28508                    min_lines: 1,
28509                    max_lines: Some(Self::MAX_LINES as usize),
28510                },
28511                buffer,
28512                None,
28513                window,
28514                cx,
28515            );
28516            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
28517            prompt.set_show_cursor_when_unfocused(false, cx);
28518            prompt.set_placeholder_text(
28519                match edit_action {
28520                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
28521                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
28522                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
28523                },
28524                window,
28525                cx,
28526            );
28527
28528            prompt
28529        });
28530
28531        Self {
28532            prompt,
28533            editor,
28534            breakpoint_anchor,
28535            breakpoint,
28536            edit_action,
28537            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
28538            block_ids: Default::default(),
28539            _subscriptions: vec![],
28540        }
28541    }
28542
28543    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
28544        self.block_ids.extend(block_ids)
28545    }
28546
28547    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
28548        if let Some(editor) = self.editor.upgrade() {
28549            let message = self
28550                .prompt
28551                .read(cx)
28552                .buffer
28553                .read(cx)
28554                .as_singleton()
28555                .expect("A multi buffer in breakpoint prompt isn't possible")
28556                .read(cx)
28557                .as_rope()
28558                .to_string();
28559
28560            editor.update(cx, |editor, cx| {
28561                editor.edit_breakpoint_at_anchor(
28562                    self.breakpoint_anchor,
28563                    self.breakpoint.clone(),
28564                    match self.edit_action {
28565                        BreakpointPromptEditAction::Log => {
28566                            BreakpointEditAction::EditLogMessage(message.into())
28567                        }
28568                        BreakpointPromptEditAction::Condition => {
28569                            BreakpointEditAction::EditCondition(message.into())
28570                        }
28571                        BreakpointPromptEditAction::HitCondition => {
28572                            BreakpointEditAction::EditHitCondition(message.into())
28573                        }
28574                    },
28575                    cx,
28576                );
28577
28578                editor.remove_blocks(self.block_ids.clone(), None, cx);
28579                cx.focus_self(window);
28580            });
28581        }
28582    }
28583
28584    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
28585        self.editor
28586            .update(cx, |editor, cx| {
28587                editor.remove_blocks(self.block_ids.clone(), None, cx);
28588                window.focus(&editor.focus_handle, cx);
28589            })
28590            .log_err();
28591    }
28592
28593    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
28594        let settings = ThemeSettings::get_global(cx);
28595        let text_style = TextStyle {
28596            color: if self.prompt.read(cx).read_only(cx) {
28597                cx.theme().colors().text_disabled
28598            } else {
28599                cx.theme().colors().text
28600            },
28601            font_family: settings.buffer_font.family.clone(),
28602            font_fallbacks: settings.buffer_font.fallbacks.clone(),
28603            font_size: settings.buffer_font_size(cx).into(),
28604            font_weight: settings.buffer_font.weight,
28605            line_height: relative(settings.buffer_line_height.value()),
28606            ..Default::default()
28607        };
28608        EditorElement::new(
28609            &self.prompt,
28610            EditorStyle {
28611                background: cx.theme().colors().editor_background,
28612                local_player: cx.theme().players().local(),
28613                text: text_style,
28614                ..Default::default()
28615            },
28616        )
28617    }
28618}
28619
28620impl Render for BreakpointPromptEditor {
28621    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28622        let editor_margins = *self.editor_margins.lock();
28623        let gutter_dimensions = editor_margins.gutter;
28624        h_flex()
28625            .key_context("Editor")
28626            .bg(cx.theme().colors().editor_background)
28627            .border_y_1()
28628            .border_color(cx.theme().status().info_border)
28629            .size_full()
28630            .py(window.line_height() / 2.5)
28631            .on_action(cx.listener(Self::confirm))
28632            .on_action(cx.listener(Self::cancel))
28633            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
28634            .child(div().flex_1().child(self.render_prompt_editor(cx)))
28635    }
28636}
28637
28638impl Focusable for BreakpointPromptEditor {
28639    fn focus_handle(&self, cx: &App) -> FocusHandle {
28640        self.prompt.focus_handle(cx)
28641    }
28642}
28643
28644fn all_edits_insertions_or_deletions(
28645    edits: &Vec<(Range<Anchor>, Arc<str>)>,
28646    snapshot: &MultiBufferSnapshot,
28647) -> bool {
28648    let mut all_insertions = true;
28649    let mut all_deletions = true;
28650
28651    for (range, new_text) in edits.iter() {
28652        let range_is_empty = range.to_offset(snapshot).is_empty();
28653        let text_is_empty = new_text.is_empty();
28654
28655        if range_is_empty != text_is_empty {
28656            if range_is_empty {
28657                all_deletions = false;
28658            } else {
28659                all_insertions = false;
28660            }
28661        } else {
28662            return false;
28663        }
28664
28665        if !all_insertions && !all_deletions {
28666            return false;
28667        }
28668    }
28669    all_insertions || all_deletions
28670}
28671
28672struct MissingEditPredictionKeybindingTooltip;
28673
28674impl Render for MissingEditPredictionKeybindingTooltip {
28675    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28676        ui::tooltip_container(cx, |container, cx| {
28677            container
28678                .flex_shrink_0()
28679                .max_w_80()
28680                .min_h(rems_from_px(124.))
28681                .justify_between()
28682                .child(
28683                    v_flex()
28684                        .flex_1()
28685                        .text_ui_sm(cx)
28686                        .child(Label::new("Conflict with Accept Keybinding"))
28687                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
28688                )
28689                .child(
28690                    h_flex()
28691                        .pb_1()
28692                        .gap_1()
28693                        .items_end()
28694                        .w_full()
28695                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
28696                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
28697                        }))
28698                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
28699                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
28700                        })),
28701                )
28702        })
28703    }
28704}
28705
28706#[derive(Debug, Clone, Copy, PartialEq)]
28707pub struct LineHighlight {
28708    pub background: Background,
28709    pub border: Option<gpui::Hsla>,
28710    pub include_gutter: bool,
28711    pub type_id: Option<TypeId>,
28712}
28713
28714struct LineManipulationResult {
28715    pub new_text: String,
28716    pub line_count_before: usize,
28717    pub line_count_after: usize,
28718}
28719
28720fn render_diff_hunk_controls(
28721    row: u32,
28722    status: &DiffHunkStatus,
28723    hunk_range: Range<Anchor>,
28724    is_created_file: bool,
28725    line_height: Pixels,
28726    editor: &Entity<Editor>,
28727    _window: &mut Window,
28728    cx: &mut App,
28729) -> AnyElement {
28730    h_flex()
28731        .h(line_height)
28732        .mr_1()
28733        .gap_1()
28734        .px_0p5()
28735        .pb_1()
28736        .border_x_1()
28737        .border_b_1()
28738        .border_color(cx.theme().colors().border_variant)
28739        .rounded_b_lg()
28740        .bg(cx.theme().colors().editor_background)
28741        .gap_1()
28742        .block_mouse_except_scroll()
28743        .shadow_md()
28744        .child(if status.has_secondary_hunk() {
28745            Button::new(("stage", row as u64), "Stage")
28746                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28747                .tooltip({
28748                    let focus_handle = editor.focus_handle(cx);
28749                    move |_window, cx| {
28750                        Tooltip::for_action_in(
28751                            "Stage Hunk",
28752                            &::git::ToggleStaged,
28753                            &focus_handle,
28754                            cx,
28755                        )
28756                    }
28757                })
28758                .on_click({
28759                    let editor = editor.clone();
28760                    move |_event, _window, cx| {
28761                        editor.update(cx, |editor, cx| {
28762                            editor.stage_or_unstage_diff_hunks(
28763                                true,
28764                                vec![hunk_range.start..hunk_range.start],
28765                                cx,
28766                            );
28767                        });
28768                    }
28769                })
28770        } else {
28771            Button::new(("unstage", row as u64), "Unstage")
28772                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28773                .tooltip({
28774                    let focus_handle = editor.focus_handle(cx);
28775                    move |_window, cx| {
28776                        Tooltip::for_action_in(
28777                            "Unstage Hunk",
28778                            &::git::ToggleStaged,
28779                            &focus_handle,
28780                            cx,
28781                        )
28782                    }
28783                })
28784                .on_click({
28785                    let editor = editor.clone();
28786                    move |_event, _window, cx| {
28787                        editor.update(cx, |editor, cx| {
28788                            editor.stage_or_unstage_diff_hunks(
28789                                false,
28790                                vec![hunk_range.start..hunk_range.start],
28791                                cx,
28792                            );
28793                        });
28794                    }
28795                })
28796        })
28797        .child(
28798            Button::new(("restore", row as u64), "Restore")
28799                .tooltip({
28800                    let focus_handle = editor.focus_handle(cx);
28801                    move |_window, cx| {
28802                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
28803                    }
28804                })
28805                .on_click({
28806                    let editor = editor.clone();
28807                    move |_event, window, cx| {
28808                        editor.update(cx, |editor, cx| {
28809                            let snapshot = editor.snapshot(window, cx);
28810                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
28811                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
28812                        });
28813                    }
28814                })
28815                .disabled(is_created_file),
28816        )
28817        .when(
28818            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
28819            |el| {
28820                el.child(
28821                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
28822                        .shape(IconButtonShape::Square)
28823                        .icon_size(IconSize::Small)
28824                        // .disabled(!has_multiple_hunks)
28825                        .tooltip({
28826                            let focus_handle = editor.focus_handle(cx);
28827                            move |_window, cx| {
28828                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
28829                            }
28830                        })
28831                        .on_click({
28832                            let editor = editor.clone();
28833                            move |_event, window, cx| {
28834                                editor.update(cx, |editor, cx| {
28835                                    let snapshot = editor.snapshot(window, cx);
28836                                    let position =
28837                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
28838                                    editor.go_to_hunk_before_or_after_position(
28839                                        &snapshot,
28840                                        position,
28841                                        Direction::Next,
28842                                        window,
28843                                        cx,
28844                                    );
28845                                    editor.expand_selected_diff_hunks(cx);
28846                                });
28847                            }
28848                        }),
28849                )
28850                .child(
28851                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
28852                        .shape(IconButtonShape::Square)
28853                        .icon_size(IconSize::Small)
28854                        // .disabled(!has_multiple_hunks)
28855                        .tooltip({
28856                            let focus_handle = editor.focus_handle(cx);
28857                            move |_window, cx| {
28858                                Tooltip::for_action_in(
28859                                    "Previous Hunk",
28860                                    &GoToPreviousHunk,
28861                                    &focus_handle,
28862                                    cx,
28863                                )
28864                            }
28865                        })
28866                        .on_click({
28867                            let editor = editor.clone();
28868                            move |_event, window, cx| {
28869                                editor.update(cx, |editor, cx| {
28870                                    let snapshot = editor.snapshot(window, cx);
28871                                    let point =
28872                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
28873                                    editor.go_to_hunk_before_or_after_position(
28874                                        &snapshot,
28875                                        point,
28876                                        Direction::Prev,
28877                                        window,
28878                                        cx,
28879                                    );
28880                                    editor.expand_selected_diff_hunks(cx);
28881                                });
28882                            }
28883                        }),
28884                )
28885            },
28886        )
28887        .into_any_element()
28888}
28889
28890pub fn multibuffer_context_lines(cx: &App) -> u32 {
28891    EditorSettings::try_get(cx)
28892        .map(|settings| settings.excerpt_context_lines)
28893        .unwrap_or(2)
28894        .min(32)
28895}