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//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::Peekable,
  181    mem,
  182    num::NonZeroU32,
  183    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(usize),
  283    DebuggerValue(usize),
  284    // LSP
  285    Hint(usize),
  286    Color(usize),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> usize {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    HighlightStyle {
  596        color: Some(cx.theme().status().hint),
  597        background_color: show_background.then(|| cx.theme().status().hint_background),
  598        ..HighlightStyle::default()
  599    }
  600}
  601
  602pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  603    EditPredictionStyles {
  604        insertion: HighlightStyle {
  605            color: Some(cx.theme().status().predictive),
  606            ..HighlightStyle::default()
  607        },
  608        whitespace: HighlightStyle {
  609            background_color: Some(cx.theme().status().created_background),
  610            ..HighlightStyle::default()
  611        },
  612    }
  613}
  614
  615type CompletionId = usize;
  616
  617pub(crate) enum EditDisplayMode {
  618    TabAccept,
  619    DiffPopover,
  620    Inline,
  621}
  622
  623enum EditPrediction {
  624    Edit {
  625        edits: Vec<(Range<Anchor>, String)>,
  626        edit_preview: Option<EditPreview>,
  627        display_mode: EditDisplayMode,
  628        snapshot: BufferSnapshot,
  629    },
  630    Move {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634}
  635
  636struct EditPredictionState {
  637    inlay_ids: Vec<InlayId>,
  638    completion: EditPrediction,
  639    completion_id: Option<SharedString>,
  640    invalidation_range: Range<Anchor>,
  641}
  642
  643enum EditPredictionSettings {
  644    Disabled,
  645    Enabled {
  646        show_in_menu: bool,
  647        preview_requires_modifier: bool,
  648    },
  649}
  650
  651enum EditPredictionHighlight {}
  652
  653#[derive(Debug, Clone)]
  654struct InlineDiagnostic {
  655    message: SharedString,
  656    group_id: usize,
  657    is_primary: bool,
  658    start: Point,
  659    severity: lsp::DiagnosticSeverity,
  660}
  661
  662pub enum MenuEditPredictionsPolicy {
  663    Never,
  664    ByProvider,
  665}
  666
  667pub enum EditPredictionPreview {
  668    /// Modifier is not pressed
  669    Inactive { released_too_fast: bool },
  670    /// Modifier pressed
  671    Active {
  672        since: Instant,
  673        previous_scroll_position: Option<ScrollAnchor>,
  674    },
  675}
  676
  677impl EditPredictionPreview {
  678    pub fn released_too_fast(&self) -> bool {
  679        match self {
  680            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  681            EditPredictionPreview::Active { .. } => false,
  682        }
  683    }
  684
  685    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  686        if let EditPredictionPreview::Active {
  687            previous_scroll_position,
  688            ..
  689        } = self
  690        {
  691            *previous_scroll_position = scroll_position;
  692        }
  693    }
  694}
  695
  696pub struct ContextMenuOptions {
  697    pub min_entries_visible: usize,
  698    pub max_entries_visible: usize,
  699    pub placement: Option<ContextMenuPlacement>,
  700}
  701
  702#[derive(Debug, Clone, PartialEq, Eq)]
  703pub enum ContextMenuPlacement {
  704    Above,
  705    Below,
  706}
  707
  708#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  709struct EditorActionId(usize);
  710
  711impl EditorActionId {
  712    pub fn post_inc(&mut self) -> Self {
  713        let answer = self.0;
  714
  715        *self = Self(answer + 1);
  716
  717        Self(answer)
  718    }
  719}
  720
  721// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  722// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  723
  724type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  725type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  726
  727#[derive(Default)]
  728struct ScrollbarMarkerState {
  729    scrollbar_size: Size<Pixels>,
  730    dirty: bool,
  731    markers: Arc<[PaintQuad]>,
  732    pending_refresh: Option<Task<Result<()>>>,
  733}
  734
  735impl ScrollbarMarkerState {
  736    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  737        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  738    }
  739}
  740
  741#[derive(Clone, Copy, PartialEq, Eq)]
  742pub enum MinimapVisibility {
  743    Disabled,
  744    Enabled {
  745        /// The configuration currently present in the users settings.
  746        setting_configuration: bool,
  747        /// Whether to override the currently set visibility from the users setting.
  748        toggle_override: bool,
  749    },
  750}
  751
  752impl MinimapVisibility {
  753    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  754        if mode.is_full() {
  755            Self::Enabled {
  756                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  757                toggle_override: false,
  758            }
  759        } else {
  760            Self::Disabled
  761        }
  762    }
  763
  764    fn hidden(&self) -> Self {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => Self::Enabled {
  770                setting_configuration,
  771                toggle_override: setting_configuration,
  772            },
  773            Self::Disabled => Self::Disabled,
  774        }
  775    }
  776
  777    fn disabled(&self) -> bool {
  778        matches!(*self, Self::Disabled)
  779    }
  780
  781    fn settings_visibility(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => setting_configuration,
  787            _ => false,
  788        }
  789    }
  790
  791    fn visible(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                toggle_override,
  796            } => setting_configuration ^ toggle_override,
  797            _ => false,
  798        }
  799    }
  800
  801    fn toggle_visibility(&self) -> Self {
  802        match *self {
  803            Self::Enabled {
  804                toggle_override,
  805                setting_configuration,
  806            } => Self::Enabled {
  807                setting_configuration,
  808                toggle_override: !toggle_override,
  809            },
  810            Self::Disabled => Self::Disabled,
  811        }
  812    }
  813}
  814
  815#[derive(Clone, Debug)]
  816struct RunnableTasks {
  817    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  818    offset: multi_buffer::Anchor,
  819    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  820    column: u32,
  821    // Values of all named captures, including those starting with '_'
  822    extra_variables: HashMap<String, String>,
  823    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  824    context_range: Range<BufferOffset>,
  825}
  826
  827impl RunnableTasks {
  828    fn resolve<'a>(
  829        &'a self,
  830        cx: &'a task::TaskContext,
  831    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  832        self.templates.iter().filter_map(|(kind, template)| {
  833            template
  834                .resolve_task(&kind.to_id_base(), cx)
  835                .map(|task| (kind.clone(), task))
  836        })
  837    }
  838}
  839
  840#[derive(Clone)]
  841pub struct ResolvedTasks {
  842    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  843    position: Anchor,
  844}
  845
  846#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  847struct BufferOffset(usize);
  848
  849/// Addons allow storing per-editor state in other crates (e.g. Vim)
  850pub trait Addon: 'static {
  851    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  852
  853    fn render_buffer_header_controls(
  854        &self,
  855        _: &ExcerptInfo,
  856        _: &Window,
  857        _: &App,
  858    ) -> Option<AnyElement> {
  859        None
  860    }
  861
  862    fn to_any(&self) -> &dyn std::any::Any;
  863
  864    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  865        None
  866    }
  867}
  868
  869struct ChangeLocation {
  870    current: Option<Vec<Anchor>>,
  871    original: Vec<Anchor>,
  872}
  873impl ChangeLocation {
  874    fn locations(&self) -> &[Anchor] {
  875        self.current.as_ref().unwrap_or(&self.original)
  876    }
  877}
  878
  879/// A set of caret positions, registered when the editor was edited.
  880pub struct ChangeList {
  881    changes: Vec<ChangeLocation>,
  882    /// Currently "selected" change.
  883    position: Option<usize>,
  884}
  885
  886impl ChangeList {
  887    pub fn new() -> Self {
  888        Self {
  889            changes: Vec::new(),
  890            position: None,
  891        }
  892    }
  893
  894    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  895    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  896    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  897        if self.changes.is_empty() {
  898            return None;
  899        }
  900
  901        let prev = self.position.unwrap_or(self.changes.len());
  902        let next = if direction == Direction::Prev {
  903            prev.saturating_sub(count)
  904        } else {
  905            (prev + count).min(self.changes.len() - 1)
  906        };
  907        self.position = Some(next);
  908        self.changes.get(next).map(|change| change.locations())
  909    }
  910
  911    /// Adds a new change to the list, resetting the change list position.
  912    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  913        self.position.take();
  914        if let Some(last) = self.changes.last_mut()
  915            && group
  916        {
  917            last.current = Some(new_positions)
  918        } else {
  919            self.changes.push(ChangeLocation {
  920                original: new_positions,
  921                current: None,
  922            });
  923        }
  924    }
  925
  926    pub fn last(&self) -> Option<&[Anchor]> {
  927        self.changes.last().map(|change| change.locations())
  928    }
  929
  930    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.original.as_slice())
  932    }
  933
  934    pub fn invert_last_group(&mut self) {
  935        if let Some(last) = self.changes.last_mut()
  936            && let Some(current) = last.current.as_mut()
  937        {
  938            mem::swap(&mut last.original, current);
  939        }
  940    }
  941}
  942
  943#[derive(Clone)]
  944struct InlineBlamePopoverState {
  945    scroll_handle: ScrollHandle,
  946    commit_message: Option<ParsedCommitMessage>,
  947    markdown: Entity<Markdown>,
  948}
  949
  950struct InlineBlamePopover {
  951    position: gpui::Point<Pixels>,
  952    hide_task: Option<Task<()>>,
  953    popover_bounds: Option<Bounds<Pixels>>,
  954    popover_state: InlineBlamePopoverState,
  955    keyboard_grace: bool,
  956}
  957
  958enum SelectionDragState {
  959    /// State when no drag related activity is detected.
  960    None,
  961    /// State when the mouse is down on a selection that is about to be dragged.
  962    ReadyToDrag {
  963        selection: Selection<Anchor>,
  964        click_position: gpui::Point<Pixels>,
  965        mouse_down_time: Instant,
  966    },
  967    /// State when the mouse is dragging the selection in the editor.
  968    Dragging {
  969        selection: Selection<Anchor>,
  970        drop_cursor: Selection<Anchor>,
  971        hide_drop_cursor: bool,
  972    },
  973}
  974
  975enum ColumnarSelectionState {
  976    FromMouse {
  977        selection_tail: Anchor,
  978        display_point: Option<DisplayPoint>,
  979    },
  980    FromSelection {
  981        selection_tail: Anchor,
  982    },
  983}
  984
  985/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  986/// a breakpoint on them.
  987#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  988struct PhantomBreakpointIndicator {
  989    display_row: DisplayRow,
  990    /// There's a small debounce between hovering over the line and showing the indicator.
  991    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  992    is_active: bool,
  993    collides_with_existing_breakpoint: bool,
  994}
  995
  996/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  997///
  998/// See the [module level documentation](self) for more information.
  999pub struct Editor {
 1000    focus_handle: FocusHandle,
 1001    last_focused_descendant: Option<WeakFocusHandle>,
 1002    /// The text buffer being edited
 1003    buffer: Entity<MultiBuffer>,
 1004    /// Map of how text in the buffer should be displayed.
 1005    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1006    pub display_map: Entity<DisplayMap>,
 1007    placeholder_display_map: Option<Entity<DisplayMap>>,
 1008    pub selections: SelectionsCollection,
 1009    pub scroll_manager: ScrollManager,
 1010    /// When inline assist editors are linked, they all render cursors because
 1011    /// typing enters text into each of them, even the ones that aren't focused.
 1012    pub(crate) show_cursor_when_unfocused: bool,
 1013    columnar_selection_state: Option<ColumnarSelectionState>,
 1014    add_selections_state: Option<AddSelectionsState>,
 1015    select_next_state: Option<SelectNextState>,
 1016    select_prev_state: Option<SelectNextState>,
 1017    selection_history: SelectionHistory,
 1018    defer_selection_effects: bool,
 1019    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1020    autoclose_regions: Vec<AutocloseRegion>,
 1021    snippet_stack: InvalidationStack<SnippetState>,
 1022    select_syntax_node_history: SelectSyntaxNodeHistory,
 1023    ime_transaction: Option<TransactionId>,
 1024    pub diagnostics_max_severity: DiagnosticSeverity,
 1025    active_diagnostics: ActiveDiagnostic,
 1026    show_inline_diagnostics: bool,
 1027    inline_diagnostics_update: Task<()>,
 1028    inline_diagnostics_enabled: bool,
 1029    diagnostics_enabled: bool,
 1030    word_completions_enabled: bool,
 1031    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1032    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1033    hard_wrap: Option<usize>,
 1034    project: Option<Entity<Project>>,
 1035    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1036    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1037    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1038    blink_manager: Entity<BlinkManager>,
 1039    show_cursor_names: bool,
 1040    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1041    pub show_local_selections: bool,
 1042    mode: EditorMode,
 1043    show_breadcrumbs: bool,
 1044    show_gutter: bool,
 1045    show_scrollbars: ScrollbarAxes,
 1046    minimap_visibility: MinimapVisibility,
 1047    offset_content: bool,
 1048    disable_expand_excerpt_buttons: bool,
 1049    show_line_numbers: Option<bool>,
 1050    use_relative_line_numbers: Option<bool>,
 1051    show_git_diff_gutter: Option<bool>,
 1052    show_code_actions: Option<bool>,
 1053    show_runnables: Option<bool>,
 1054    show_breakpoints: Option<bool>,
 1055    show_wrap_guides: Option<bool>,
 1056    show_indent_guides: Option<bool>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_edit_prediction: Option<EditPredictionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    edit_predictions_hidden_for_vim_mode: bool,
 1104    show_edit_predictions_override: Option<bool>,
 1105    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1178}
 1179
 1180#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1181enum NextScrollCursorCenterTopBottom {
 1182    #[default]
 1183    Center,
 1184    Top,
 1185    Bottom,
 1186}
 1187
 1188impl NextScrollCursorCenterTopBottom {
 1189    fn next(&self) -> Self {
 1190        match self {
 1191            Self::Center => Self::Top,
 1192            Self::Top => Self::Bottom,
 1193            Self::Bottom => Self::Center,
 1194        }
 1195    }
 1196}
 1197
 1198#[derive(Clone)]
 1199pub struct EditorSnapshot {
 1200    pub mode: EditorMode,
 1201    show_gutter: bool,
 1202    show_line_numbers: Option<bool>,
 1203    show_git_diff_gutter: Option<bool>,
 1204    show_code_actions: Option<bool>,
 1205    show_runnables: Option<bool>,
 1206    show_breakpoints: Option<bool>,
 1207    git_blame_gutter_max_author_length: Option<usize>,
 1208    pub display_snapshot: DisplaySnapshot,
 1209    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1210    is_focused: bool,
 1211    scroll_anchor: ScrollAnchor,
 1212    ongoing_scroll: OngoingScroll,
 1213    current_line_highlight: CurrentLineHighlight,
 1214    gutter_hovered: bool,
 1215}
 1216
 1217#[derive(Default, Debug, Clone, Copy)]
 1218pub struct GutterDimensions {
 1219    pub left_padding: Pixels,
 1220    pub right_padding: Pixels,
 1221    pub width: Pixels,
 1222    pub margin: Pixels,
 1223    pub git_blame_entries_width: Option<Pixels>,
 1224}
 1225
 1226impl GutterDimensions {
 1227    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1228        Self {
 1229            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1230            ..Default::default()
 1231        }
 1232    }
 1233
 1234    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1235        -cx.text_system().descent(font_id, font_size)
 1236    }
 1237    /// The full width of the space taken up by the gutter.
 1238    pub fn full_width(&self) -> Pixels {
 1239        self.margin + self.width
 1240    }
 1241
 1242    /// The width of the space reserved for the fold indicators,
 1243    /// use alongside 'justify_end' and `gutter_width` to
 1244    /// right align content with the line numbers
 1245    pub fn fold_area_width(&self) -> Pixels {
 1246        self.margin + self.right_padding
 1247    }
 1248}
 1249
 1250struct CharacterDimensions {
 1251    em_width: Pixels,
 1252    em_advance: Pixels,
 1253    line_height: Pixels,
 1254}
 1255
 1256#[derive(Debug)]
 1257pub struct RemoteSelection {
 1258    pub replica_id: ReplicaId,
 1259    pub selection: Selection<Anchor>,
 1260    pub cursor_shape: CursorShape,
 1261    pub collaborator_id: CollaboratorId,
 1262    pub line_mode: bool,
 1263    pub user_name: Option<SharedString>,
 1264    pub color: PlayerColor,
 1265}
 1266
 1267#[derive(Clone, Debug)]
 1268struct SelectionHistoryEntry {
 1269    selections: Arc<[Selection<Anchor>]>,
 1270    select_next_state: Option<SelectNextState>,
 1271    select_prev_state: Option<SelectNextState>,
 1272    add_selections_state: Option<AddSelectionsState>,
 1273}
 1274
 1275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1276enum SelectionHistoryMode {
 1277    Normal,
 1278    Undoing,
 1279    Redoing,
 1280    Skipping,
 1281}
 1282
 1283#[derive(Clone, PartialEq, Eq, Hash)]
 1284struct HoveredCursor {
 1285    replica_id: u16,
 1286    selection_id: usize,
 1287}
 1288
 1289impl Default for SelectionHistoryMode {
 1290    fn default() -> Self {
 1291        Self::Normal
 1292    }
 1293}
 1294
 1295#[derive(Debug)]
 1296/// SelectionEffects controls the side-effects of updating the selection.
 1297///
 1298/// The default behaviour does "what you mostly want":
 1299/// - it pushes to the nav history if the cursor moved by >10 lines
 1300/// - it re-triggers completion requests
 1301/// - it scrolls to fit
 1302///
 1303/// You might want to modify these behaviours. For example when doing a "jump"
 1304/// like go to definition, we always want to add to nav history; but when scrolling
 1305/// in vim mode we never do.
 1306///
 1307/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1308/// move.
 1309#[derive(Clone)]
 1310pub struct SelectionEffects {
 1311    nav_history: Option<bool>,
 1312    completions: bool,
 1313    scroll: Option<Autoscroll>,
 1314}
 1315
 1316impl Default for SelectionEffects {
 1317    fn default() -> Self {
 1318        Self {
 1319            nav_history: None,
 1320            completions: true,
 1321            scroll: Some(Autoscroll::fit()),
 1322        }
 1323    }
 1324}
 1325impl SelectionEffects {
 1326    pub fn scroll(scroll: Autoscroll) -> Self {
 1327        Self {
 1328            scroll: Some(scroll),
 1329            ..Default::default()
 1330        }
 1331    }
 1332
 1333    pub fn no_scroll() -> Self {
 1334        Self {
 1335            scroll: None,
 1336            ..Default::default()
 1337        }
 1338    }
 1339
 1340    pub fn completions(self, completions: bool) -> Self {
 1341        Self {
 1342            completions,
 1343            ..self
 1344        }
 1345    }
 1346
 1347    pub fn nav_history(self, nav_history: bool) -> Self {
 1348        Self {
 1349            nav_history: Some(nav_history),
 1350            ..self
 1351        }
 1352    }
 1353}
 1354
 1355struct DeferredSelectionEffectsState {
 1356    changed: bool,
 1357    effects: SelectionEffects,
 1358    old_cursor_position: Anchor,
 1359    history_entry: SelectionHistoryEntry,
 1360}
 1361
 1362#[derive(Default)]
 1363struct SelectionHistory {
 1364    #[allow(clippy::type_complexity)]
 1365    selections_by_transaction:
 1366        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1367    mode: SelectionHistoryMode,
 1368    undo_stack: VecDeque<SelectionHistoryEntry>,
 1369    redo_stack: VecDeque<SelectionHistoryEntry>,
 1370}
 1371
 1372impl SelectionHistory {
 1373    #[track_caller]
 1374    fn insert_transaction(
 1375        &mut self,
 1376        transaction_id: TransactionId,
 1377        selections: Arc<[Selection<Anchor>]>,
 1378    ) {
 1379        if selections.is_empty() {
 1380            log::error!(
 1381                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1382                std::panic::Location::caller()
 1383            );
 1384            return;
 1385        }
 1386        self.selections_by_transaction
 1387            .insert(transaction_id, (selections, None));
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction(
 1392        &self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get(&transaction_id)
 1396    }
 1397
 1398    #[allow(clippy::type_complexity)]
 1399    fn transaction_mut(
 1400        &mut self,
 1401        transaction_id: TransactionId,
 1402    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1403        self.selections_by_transaction.get_mut(&transaction_id)
 1404    }
 1405
 1406    fn push(&mut self, entry: SelectionHistoryEntry) {
 1407        if !entry.selections.is_empty() {
 1408            match self.mode {
 1409                SelectionHistoryMode::Normal => {
 1410                    self.push_undo(entry);
 1411                    self.redo_stack.clear();
 1412                }
 1413                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1414                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1415                SelectionHistoryMode::Skipping => {}
 1416            }
 1417        }
 1418    }
 1419
 1420    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1421        if self
 1422            .undo_stack
 1423            .back()
 1424            .is_none_or(|e| e.selections != entry.selections)
 1425        {
 1426            self.undo_stack.push_back(entry);
 1427            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1428                self.undo_stack.pop_front();
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .redo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.redo_stack.push_back(entry);
 1440            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.redo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445}
 1446
 1447#[derive(Clone, Copy)]
 1448pub struct RowHighlightOptions {
 1449    pub autoscroll: bool,
 1450    pub include_gutter: bool,
 1451}
 1452
 1453impl Default for RowHighlightOptions {
 1454    fn default() -> Self {
 1455        Self {
 1456            autoscroll: Default::default(),
 1457            include_gutter: true,
 1458        }
 1459    }
 1460}
 1461
 1462struct RowHighlight {
 1463    index: usize,
 1464    range: Range<Anchor>,
 1465    color: Hsla,
 1466    options: RowHighlightOptions,
 1467    type_id: TypeId,
 1468}
 1469
 1470#[derive(Clone, Debug)]
 1471struct AddSelectionsState {
 1472    groups: Vec<AddSelectionsGroup>,
 1473}
 1474
 1475#[derive(Clone, Debug)]
 1476struct AddSelectionsGroup {
 1477    above: bool,
 1478    stack: Vec<usize>,
 1479}
 1480
 1481#[derive(Clone)]
 1482struct SelectNextState {
 1483    query: AhoCorasick,
 1484    wordwise: bool,
 1485    done: bool,
 1486}
 1487
 1488impl std::fmt::Debug for SelectNextState {
 1489    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1490        f.debug_struct(std::any::type_name::<Self>())
 1491            .field("wordwise", &self.wordwise)
 1492            .field("done", &self.done)
 1493            .finish()
 1494    }
 1495}
 1496
 1497#[derive(Debug)]
 1498struct AutocloseRegion {
 1499    selection_id: usize,
 1500    range: Range<Anchor>,
 1501    pair: BracketPair,
 1502}
 1503
 1504#[derive(Debug)]
 1505struct SnippetState {
 1506    ranges: Vec<Vec<Range<Anchor>>>,
 1507    active_index: usize,
 1508    choices: Vec<Option<Vec<String>>>,
 1509}
 1510
 1511#[doc(hidden)]
 1512pub struct RenameState {
 1513    pub range: Range<Anchor>,
 1514    pub old_name: Arc<str>,
 1515    pub editor: Entity<Editor>,
 1516    block_id: CustomBlockId,
 1517}
 1518
 1519struct InvalidationStack<T>(Vec<T>);
 1520
 1521struct RegisteredEditPredictionProvider {
 1522    provider: Arc<dyn EditPredictionProviderHandle>,
 1523    _subscription: Subscription,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527pub struct ActiveDiagnosticGroup {
 1528    pub active_range: Range<Anchor>,
 1529    pub active_message: String,
 1530    pub group_id: usize,
 1531    pub blocks: HashSet<CustomBlockId>,
 1532}
 1533
 1534#[derive(Debug, PartialEq, Eq)]
 1535
 1536pub(crate) enum ActiveDiagnostic {
 1537    None,
 1538    All,
 1539    Group(ActiveDiagnosticGroup),
 1540}
 1541
 1542#[derive(Serialize, Deserialize, Clone, Debug)]
 1543pub struct ClipboardSelection {
 1544    /// The number of bytes in this selection.
 1545    pub len: usize,
 1546    /// Whether this was a full-line selection.
 1547    pub is_entire_line: bool,
 1548    /// The indentation of the first line when this content was originally copied.
 1549    pub first_line_indent: u32,
 1550}
 1551
 1552// selections, scroll behavior, was newest selection reversed
 1553type SelectSyntaxNodeHistoryState = (
 1554    Box<[Selection<usize>]>,
 1555    SelectSyntaxNodeScrollBehavior,
 1556    bool,
 1557);
 1558
 1559#[derive(Default)]
 1560struct SelectSyntaxNodeHistory {
 1561    stack: Vec<SelectSyntaxNodeHistoryState>,
 1562    // disable temporarily to allow changing selections without losing the stack
 1563    pub disable_clearing: bool,
 1564}
 1565
 1566impl SelectSyntaxNodeHistory {
 1567    pub fn try_clear(&mut self) {
 1568        if !self.disable_clearing {
 1569            self.stack.clear();
 1570        }
 1571    }
 1572
 1573    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1574        self.stack.push(selection);
 1575    }
 1576
 1577    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1578        self.stack.pop()
 1579    }
 1580}
 1581
 1582enum SelectSyntaxNodeScrollBehavior {
 1583    CursorTop,
 1584    FitSelection,
 1585    CursorBottom,
 1586}
 1587
 1588#[derive(Debug)]
 1589pub(crate) struct NavigationData {
 1590    cursor_anchor: Anchor,
 1591    cursor_position: Point,
 1592    scroll_anchor: ScrollAnchor,
 1593    scroll_top_row: u32,
 1594}
 1595
 1596#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1597pub enum GotoDefinitionKind {
 1598    Symbol,
 1599    Declaration,
 1600    Type,
 1601    Implementation,
 1602}
 1603
 1604#[derive(Debug, Clone)]
 1605enum InlayHintRefreshReason {
 1606    ModifiersChanged(bool),
 1607    Toggle(bool),
 1608    SettingsChange(InlayHintSettings),
 1609    NewLinesShown,
 1610    BufferEdited(HashSet<Arc<Language>>),
 1611    RefreshRequested,
 1612    ExcerptsRemoved(Vec<ExcerptId>),
 1613}
 1614
 1615impl InlayHintRefreshReason {
 1616    fn description(&self) -> &'static str {
 1617        match self {
 1618            Self::ModifiersChanged(_) => "modifiers changed",
 1619            Self::Toggle(_) => "toggle",
 1620            Self::SettingsChange(_) => "settings change",
 1621            Self::NewLinesShown => "new lines shown",
 1622            Self::BufferEdited(_) => "buffer edited",
 1623            Self::RefreshRequested => "refresh requested",
 1624            Self::ExcerptsRemoved(_) => "excerpts removed",
 1625        }
 1626    }
 1627}
 1628
 1629pub enum FormatTarget {
 1630    Buffers(HashSet<Entity<Buffer>>),
 1631    Ranges(Vec<Range<MultiBufferPoint>>),
 1632}
 1633
 1634pub(crate) struct FocusedBlock {
 1635    id: BlockId,
 1636    focus_handle: WeakFocusHandle,
 1637}
 1638
 1639#[derive(Clone)]
 1640enum JumpData {
 1641    MultiBufferRow {
 1642        row: MultiBufferRow,
 1643        line_offset_from_top: u32,
 1644    },
 1645    MultiBufferPoint {
 1646        excerpt_id: ExcerptId,
 1647        position: Point,
 1648        anchor: text::Anchor,
 1649        line_offset_from_top: u32,
 1650    },
 1651}
 1652
 1653pub enum MultibufferSelectionMode {
 1654    First,
 1655    All,
 1656}
 1657
 1658#[derive(Clone, Copy, Debug, Default)]
 1659pub struct RewrapOptions {
 1660    pub override_language_settings: bool,
 1661    pub preserve_existing_whitespace: bool,
 1662}
 1663
 1664impl Editor {
 1665    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1666        let buffer = cx.new(|cx| Buffer::local("", cx));
 1667        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1668        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1669    }
 1670
 1671    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1672        let buffer = cx.new(|cx| Buffer::local("", cx));
 1673        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1674        Self::new(EditorMode::full(), buffer, None, window, cx)
 1675    }
 1676
 1677    pub fn auto_height(
 1678        min_lines: usize,
 1679        max_lines: usize,
 1680        window: &mut Window,
 1681        cx: &mut Context<Self>,
 1682    ) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(
 1686            EditorMode::AutoHeight {
 1687                min_lines,
 1688                max_lines: Some(max_lines),
 1689            },
 1690            buffer,
 1691            None,
 1692            window,
 1693            cx,
 1694        )
 1695    }
 1696
 1697    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1698    /// The editor grows as tall as needed to fit its content.
 1699    pub fn auto_height_unbounded(
 1700        min_lines: usize,
 1701        window: &mut Window,
 1702        cx: &mut Context<Self>,
 1703    ) -> Self {
 1704        let buffer = cx.new(|cx| Buffer::local("", cx));
 1705        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1706        Self::new(
 1707            EditorMode::AutoHeight {
 1708                min_lines,
 1709                max_lines: None,
 1710            },
 1711            buffer,
 1712            None,
 1713            window,
 1714            cx,
 1715        )
 1716    }
 1717
 1718    pub fn for_buffer(
 1719        buffer: Entity<Buffer>,
 1720        project: Option<Entity<Project>>,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(EditorMode::full(), buffer, project, window, cx)
 1726    }
 1727
 1728    pub fn for_multibuffer(
 1729        buffer: Entity<MultiBuffer>,
 1730        project: Option<Entity<Project>>,
 1731        window: &mut Window,
 1732        cx: &mut Context<Self>,
 1733    ) -> Self {
 1734        Self::new(EditorMode::full(), buffer, project, window, cx)
 1735    }
 1736
 1737    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1738        let mut clone = Self::new(
 1739            self.mode.clone(),
 1740            self.buffer.clone(),
 1741            self.project.clone(),
 1742            window,
 1743            cx,
 1744        );
 1745        self.display_map.update(cx, |display_map, cx| {
 1746            let snapshot = display_map.snapshot(cx);
 1747            clone.display_map.update(cx, |display_map, cx| {
 1748                display_map.set_state(&snapshot, cx);
 1749            });
 1750        });
 1751        clone.folds_did_change(cx);
 1752        clone.selections.clone_state(&self.selections);
 1753        clone.scroll_manager.clone_state(&self.scroll_manager);
 1754        clone.searchable = self.searchable;
 1755        clone.read_only = self.read_only;
 1756        clone
 1757    }
 1758
 1759    pub fn new(
 1760        mode: EditorMode,
 1761        buffer: Entity<MultiBuffer>,
 1762        project: Option<Entity<Project>>,
 1763        window: &mut Window,
 1764        cx: &mut Context<Self>,
 1765    ) -> Self {
 1766        Editor::new_internal(mode, buffer, project, None, window, cx)
 1767    }
 1768
 1769    fn new_internal(
 1770        mode: EditorMode,
 1771        buffer: Entity<MultiBuffer>,
 1772        project: Option<Entity<Project>>,
 1773        display_map: Option<Entity<DisplayMap>>,
 1774        window: &mut Window,
 1775        cx: &mut Context<Self>,
 1776    ) -> Self {
 1777        debug_assert!(
 1778            display_map.is_none() || mode.is_minimap(),
 1779            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1780        );
 1781
 1782        let full_mode = mode.is_full();
 1783        let is_minimap = mode.is_minimap();
 1784        let diagnostics_max_severity = if full_mode {
 1785            EditorSettings::get_global(cx)
 1786                .diagnostics_max_severity
 1787                .unwrap_or(DiagnosticSeverity::Hint)
 1788        } else {
 1789            DiagnosticSeverity::Off
 1790        };
 1791        let style = window.text_style();
 1792        let font_size = style.font_size.to_pixels(window.rem_size());
 1793        let editor = cx.entity().downgrade();
 1794        let fold_placeholder = FoldPlaceholder {
 1795            constrain_width: false,
 1796            render: Arc::new(move |fold_id, fold_range, cx| {
 1797                let editor = editor.clone();
 1798                div()
 1799                    .id(fold_id)
 1800                    .bg(cx.theme().colors().ghost_element_background)
 1801                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1802                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1803                    .rounded_xs()
 1804                    .size_full()
 1805                    .cursor_pointer()
 1806                    .child("")
 1807                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1808                    .on_click(move |_, _window, cx| {
 1809                        editor
 1810                            .update(cx, |editor, cx| {
 1811                                editor.unfold_ranges(
 1812                                    &[fold_range.start..fold_range.end],
 1813                                    true,
 1814                                    false,
 1815                                    cx,
 1816                                );
 1817                                cx.stop_propagation();
 1818                            })
 1819                            .ok();
 1820                    })
 1821                    .into_any()
 1822            }),
 1823            merge_adjacent: true,
 1824            ..FoldPlaceholder::default()
 1825        };
 1826        let display_map = display_map.unwrap_or_else(|| {
 1827            cx.new(|cx| {
 1828                DisplayMap::new(
 1829                    buffer.clone(),
 1830                    style.font(),
 1831                    font_size,
 1832                    None,
 1833                    FILE_HEADER_HEIGHT,
 1834                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1835                    fold_placeholder,
 1836                    diagnostics_max_severity,
 1837                    cx,
 1838                )
 1839            })
 1840        });
 1841
 1842        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1843
 1844        let blink_manager = cx.new(|cx| {
 1845            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1846            if is_minimap {
 1847                blink_manager.disable(cx);
 1848            }
 1849            blink_manager
 1850        });
 1851
 1852        let soft_wrap_mode_override =
 1853            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1854
 1855        let mut project_subscriptions = Vec::new();
 1856        if full_mode && let Some(project) = project.as_ref() {
 1857            project_subscriptions.push(cx.subscribe_in(
 1858                project,
 1859                window,
 1860                |editor, _, event, window, cx| match event {
 1861                    project::Event::RefreshCodeLens => {
 1862                        // we always query lens with actions, without storing them, always refreshing them
 1863                    }
 1864                    project::Event::RefreshInlayHints => {
 1865                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1866                    }
 1867                    project::Event::LanguageServerAdded(..)
 1868                    | project::Event::LanguageServerRemoved(..) => {
 1869                        if editor.tasks_update_task.is_none() {
 1870                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1871                        }
 1872                    }
 1873                    project::Event::SnippetEdit(id, snippet_edits) => {
 1874                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1875                            let focus_handle = editor.focus_handle(cx);
 1876                            if focus_handle.is_focused(window) {
 1877                                let snapshot = buffer.read(cx).snapshot();
 1878                                for (range, snippet) in snippet_edits {
 1879                                    let editor_range =
 1880                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1881                                    editor
 1882                                        .insert_snippet(
 1883                                            &[editor_range],
 1884                                            snippet.clone(),
 1885                                            window,
 1886                                            cx,
 1887                                        )
 1888                                        .ok();
 1889                                }
 1890                            }
 1891                        }
 1892                    }
 1893                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1894                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1895                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1896                        }
 1897                    }
 1898
 1899                    project::Event::EntryRenamed(transaction) => {
 1900                        let Some(workspace) = editor.workspace() else {
 1901                            return;
 1902                        };
 1903                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1904                        else {
 1905                            return;
 1906                        };
 1907                        if active_editor.entity_id() == cx.entity_id() {
 1908                            let edited_buffers_already_open = {
 1909                                let other_editors: Vec<Entity<Editor>> = workspace
 1910                                    .read(cx)
 1911                                    .panes()
 1912                                    .iter()
 1913                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1914                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1915                                    .collect();
 1916
 1917                                transaction.0.keys().all(|buffer| {
 1918                                    other_editors.iter().any(|editor| {
 1919                                        let multi_buffer = editor.read(cx).buffer();
 1920                                        multi_buffer.read(cx).is_singleton()
 1921                                            && multi_buffer.read(cx).as_singleton().map_or(
 1922                                                false,
 1923                                                |singleton| {
 1924                                                    singleton.entity_id() == buffer.entity_id()
 1925                                                },
 1926                                            )
 1927                                    })
 1928                                })
 1929                            };
 1930
 1931                            if !edited_buffers_already_open {
 1932                                let workspace = workspace.downgrade();
 1933                                let transaction = transaction.clone();
 1934                                cx.defer_in(window, move |_, window, cx| {
 1935                                    cx.spawn_in(window, async move |editor, cx| {
 1936                                        Self::open_project_transaction(
 1937                                            &editor,
 1938                                            workspace,
 1939                                            transaction,
 1940                                            "Rename".to_string(),
 1941                                            cx,
 1942                                        )
 1943                                        .await
 1944                                        .ok()
 1945                                    })
 1946                                    .detach();
 1947                                });
 1948                            }
 1949                        }
 1950                    }
 1951
 1952                    _ => {}
 1953                },
 1954            ));
 1955            if let Some(task_inventory) = project
 1956                .read(cx)
 1957                .task_store()
 1958                .read(cx)
 1959                .task_inventory()
 1960                .cloned()
 1961            {
 1962                project_subscriptions.push(cx.observe_in(
 1963                    &task_inventory,
 1964                    window,
 1965                    |editor, _, window, cx| {
 1966                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1967                    },
 1968                ));
 1969            };
 1970
 1971            project_subscriptions.push(cx.subscribe_in(
 1972                &project.read(cx).breakpoint_store(),
 1973                window,
 1974                |editor, _, event, window, cx| match event {
 1975                    BreakpointStoreEvent::ClearDebugLines => {
 1976                        editor.clear_row_highlights::<ActiveDebugLine>();
 1977                        editor.refresh_inline_values(cx);
 1978                    }
 1979                    BreakpointStoreEvent::SetDebugLine => {
 1980                        if editor.go_to_active_debug_line(window, cx) {
 1981                            cx.stop_propagation();
 1982                        }
 1983
 1984                        editor.refresh_inline_values(cx);
 1985                    }
 1986                    _ => {}
 1987                },
 1988            ));
 1989            let git_store = project.read(cx).git_store().clone();
 1990            let project = project.clone();
 1991            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1992                if let GitStoreEvent::RepositoryUpdated(
 1993                    _,
 1994                    RepositoryEvent::Updated {
 1995                        new_instance: true, ..
 1996                    },
 1997                    _,
 1998                ) = event
 1999                {
 2000                    this.load_diff_task = Some(
 2001                        update_uncommitted_diff_for_buffer(
 2002                            cx.entity(),
 2003                            &project,
 2004                            this.buffer.read(cx).all_buffers(),
 2005                            this.buffer.clone(),
 2006                            cx,
 2007                        )
 2008                        .shared(),
 2009                    );
 2010                }
 2011            }));
 2012        }
 2013
 2014        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2015
 2016        let inlay_hint_settings =
 2017            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2018        let focus_handle = cx.focus_handle();
 2019        if !is_minimap {
 2020            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2021                .detach();
 2022            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2023                .detach();
 2024            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2025                .detach();
 2026            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2027                .detach();
 2028            cx.observe_pending_input(window, Self::observe_pending_input)
 2029                .detach();
 2030        }
 2031
 2032        let show_indent_guides =
 2033            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2034                Some(false)
 2035            } else {
 2036                None
 2037            };
 2038
 2039        let breakpoint_store = match (&mode, project.as_ref()) {
 2040            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2041            _ => None,
 2042        };
 2043
 2044        let mut code_action_providers = Vec::new();
 2045        let mut load_uncommitted_diff = None;
 2046        if let Some(project) = project.clone() {
 2047            load_uncommitted_diff = Some(
 2048                update_uncommitted_diff_for_buffer(
 2049                    cx.entity(),
 2050                    &project,
 2051                    buffer.read(cx).all_buffers(),
 2052                    buffer.clone(),
 2053                    cx,
 2054                )
 2055                .shared(),
 2056            );
 2057            code_action_providers.push(Rc::new(project) as Rc<_>);
 2058        }
 2059
 2060        let mut editor = Self {
 2061            focus_handle,
 2062            show_cursor_when_unfocused: false,
 2063            last_focused_descendant: None,
 2064            buffer: buffer.clone(),
 2065            display_map: display_map.clone(),
 2066            placeholder_display_map: None,
 2067            selections,
 2068            scroll_manager: ScrollManager::new(cx),
 2069            columnar_selection_state: None,
 2070            add_selections_state: None,
 2071            select_next_state: None,
 2072            select_prev_state: None,
 2073            selection_history: SelectionHistory::default(),
 2074            defer_selection_effects: false,
 2075            deferred_selection_effects_state: None,
 2076            autoclose_regions: Vec::new(),
 2077            snippet_stack: InvalidationStack::default(),
 2078            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2079            ime_transaction: None,
 2080            active_diagnostics: ActiveDiagnostic::None,
 2081            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2082            inline_diagnostics_update: Task::ready(()),
 2083            inline_diagnostics: Vec::new(),
 2084            soft_wrap_mode_override,
 2085            diagnostics_max_severity,
 2086            hard_wrap: None,
 2087            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2088            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2089            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2090            project,
 2091            blink_manager: blink_manager.clone(),
 2092            show_local_selections: true,
 2093            show_scrollbars: ScrollbarAxes {
 2094                horizontal: full_mode,
 2095                vertical: full_mode,
 2096            },
 2097            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2098            offset_content: !matches!(mode, EditorMode::SingleLine),
 2099            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2100            show_gutter: full_mode,
 2101            show_line_numbers: (!full_mode).then_some(false),
 2102            use_relative_line_numbers: None,
 2103            disable_expand_excerpt_buttons: !full_mode,
 2104            show_git_diff_gutter: None,
 2105            show_code_actions: None,
 2106            show_runnables: None,
 2107            show_breakpoints: None,
 2108            show_wrap_guides: None,
 2109            show_indent_guides,
 2110            highlight_order: 0,
 2111            highlighted_rows: HashMap::default(),
 2112            background_highlights: HashMap::default(),
 2113            gutter_highlights: HashMap::default(),
 2114            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2115            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2116            nav_history: None,
 2117            context_menu: RefCell::new(None),
 2118            context_menu_options: None,
 2119            mouse_context_menu: None,
 2120            completion_tasks: Vec::new(),
 2121            inline_blame_popover: None,
 2122            inline_blame_popover_show_task: None,
 2123            signature_help_state: SignatureHelpState::default(),
 2124            auto_signature_help: None,
 2125            find_all_references_task_sources: Vec::new(),
 2126            next_completion_id: 0,
 2127            next_inlay_id: 0,
 2128            code_action_providers,
 2129            available_code_actions: None,
 2130            code_actions_task: None,
 2131            quick_selection_highlight_task: None,
 2132            debounced_selection_highlight_task: None,
 2133            document_highlights_task: None,
 2134            linked_editing_range_task: None,
 2135            pending_rename: None,
 2136            searchable: !is_minimap,
 2137            cursor_shape: EditorSettings::get_global(cx)
 2138                .cursor_shape
 2139                .unwrap_or_default(),
 2140            current_line_highlight: None,
 2141            autoindent_mode: Some(AutoindentMode::EachLine),
 2142            collapse_matches: false,
 2143            workspace: None,
 2144            input_enabled: !is_minimap,
 2145            use_modal_editing: full_mode,
 2146            read_only: is_minimap,
 2147            use_autoclose: true,
 2148            use_auto_surround: true,
 2149            auto_replace_emoji_shortcode: false,
 2150            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2151            leader_id: None,
 2152            remote_id: None,
 2153            hover_state: HoverState::default(),
 2154            pending_mouse_down: None,
 2155            hovered_link_state: None,
 2156            edit_prediction_provider: None,
 2157            active_edit_prediction: None,
 2158            stale_edit_prediction_in_menu: None,
 2159            edit_prediction_preview: EditPredictionPreview::Inactive {
 2160                released_too_fast: false,
 2161            },
 2162            inline_diagnostics_enabled: full_mode,
 2163            diagnostics_enabled: full_mode,
 2164            word_completions_enabled: full_mode,
 2165            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2166            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2167            gutter_hovered: false,
 2168            pixel_position_of_newest_cursor: None,
 2169            last_bounds: None,
 2170            last_position_map: None,
 2171            expect_bounds_change: None,
 2172            gutter_dimensions: GutterDimensions::default(),
 2173            style: None,
 2174            show_cursor_names: false,
 2175            hovered_cursors: HashMap::default(),
 2176            next_editor_action_id: EditorActionId::default(),
 2177            editor_actions: Rc::default(),
 2178            edit_predictions_hidden_for_vim_mode: false,
 2179            show_edit_predictions_override: None,
 2180            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2181            edit_prediction_settings: EditPredictionSettings::Disabled,
 2182            edit_prediction_indent_conflict: false,
 2183            edit_prediction_requires_modifier_in_indent_conflict: true,
 2184            custom_context_menu: None,
 2185            show_git_blame_gutter: false,
 2186            show_git_blame_inline: false,
 2187            show_selection_menu: None,
 2188            show_git_blame_inline_delay_task: None,
 2189            git_blame_inline_enabled: full_mode
 2190                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2191            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2192            serialize_dirty_buffers: !is_minimap
 2193                && ProjectSettings::get_global(cx)
 2194                    .session
 2195                    .restore_unsaved_buffers,
 2196            blame: None,
 2197            blame_subscription: None,
 2198            tasks: BTreeMap::default(),
 2199
 2200            breakpoint_store,
 2201            gutter_breakpoint_indicator: (None, None),
 2202            hovered_diff_hunk_row: None,
 2203            _subscriptions: (!is_minimap)
 2204                .then(|| {
 2205                    vec![
 2206                        cx.observe(&buffer, Self::on_buffer_changed),
 2207                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2208                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2209                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2210                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2211                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2212                        cx.observe_window_activation(window, |editor, window, cx| {
 2213                            let active = window.is_window_active();
 2214                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2215                                if active {
 2216                                    blink_manager.enable(cx);
 2217                                } else {
 2218                                    blink_manager.disable(cx);
 2219                                }
 2220                            });
 2221                            if active {
 2222                                editor.show_mouse_cursor(cx);
 2223                            }
 2224                        }),
 2225                    ]
 2226                })
 2227                .unwrap_or_default(),
 2228            tasks_update_task: None,
 2229            pull_diagnostics_task: Task::ready(()),
 2230            colors: None,
 2231            next_color_inlay_id: 0,
 2232            linked_edit_ranges: Default::default(),
 2233            in_project_search: false,
 2234            previous_search_ranges: None,
 2235            breadcrumb_header: None,
 2236            focused_block: None,
 2237            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2238            addons: HashMap::default(),
 2239            registered_buffers: HashMap::default(),
 2240            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2241            selection_mark_mode: false,
 2242            toggle_fold_multiple_buffers: Task::ready(()),
 2243            serialize_selections: Task::ready(()),
 2244            serialize_folds: Task::ready(()),
 2245            text_style_refinement: None,
 2246            load_diff_task: load_uncommitted_diff,
 2247            temporary_diff_override: false,
 2248            mouse_cursor_hidden: false,
 2249            minimap: None,
 2250            hide_mouse_mode: EditorSettings::get_global(cx)
 2251                .hide_mouse
 2252                .unwrap_or_default(),
 2253            change_list: ChangeList::new(),
 2254            mode,
 2255            selection_drag_state: SelectionDragState::None,
 2256            folding_newlines: Task::ready(()),
 2257            lookup_key: None,
 2258        };
 2259
 2260        if is_minimap {
 2261            return editor;
 2262        }
 2263
 2264        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2265            editor
 2266                ._subscriptions
 2267                .push(cx.observe(breakpoints, |_, _, cx| {
 2268                    cx.notify();
 2269                }));
 2270        }
 2271        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2272        editor._subscriptions.extend(project_subscriptions);
 2273
 2274        editor._subscriptions.push(cx.subscribe_in(
 2275            &cx.entity(),
 2276            window,
 2277            |editor, _, e: &EditorEvent, window, cx| match e {
 2278                EditorEvent::ScrollPositionChanged { local, .. } => {
 2279                    if *local {
 2280                        let new_anchor = editor.scroll_manager.anchor();
 2281                        let snapshot = editor.snapshot(window, cx);
 2282                        editor.update_restoration_data(cx, move |data| {
 2283                            data.scroll_position = (
 2284                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2285                                new_anchor.offset,
 2286                            );
 2287                        });
 2288                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2289                        editor.inline_blame_popover.take();
 2290                    }
 2291                }
 2292                EditorEvent::Edited { .. } => {
 2293                    if !vim_enabled(cx) {
 2294                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2295                        let pop_state = editor
 2296                            .change_list
 2297                            .last()
 2298                            .map(|previous| {
 2299                                previous.len() == selections.len()
 2300                                    && previous.iter().enumerate().all(|(ix, p)| {
 2301                                        p.to_display_point(&map).row()
 2302                                            == selections[ix].head().row()
 2303                                    })
 2304                            })
 2305                            .unwrap_or(false);
 2306                        let new_positions = selections
 2307                            .into_iter()
 2308                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2309                            .collect();
 2310                        editor
 2311                            .change_list
 2312                            .push_to_change_list(pop_state, new_positions);
 2313                    }
 2314                }
 2315                _ => (),
 2316            },
 2317        ));
 2318
 2319        if let Some(dap_store) = editor
 2320            .project
 2321            .as_ref()
 2322            .map(|project| project.read(cx).dap_store())
 2323        {
 2324            let weak_editor = cx.weak_entity();
 2325
 2326            editor
 2327                ._subscriptions
 2328                .push(
 2329                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2330                        let session_entity = cx.entity();
 2331                        weak_editor
 2332                            .update(cx, |editor, cx| {
 2333                                editor._subscriptions.push(
 2334                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2335                                );
 2336                            })
 2337                            .ok();
 2338                    }),
 2339                );
 2340
 2341            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2342                editor
 2343                    ._subscriptions
 2344                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2345            }
 2346        }
 2347
 2348        // skip adding the initial selection to selection history
 2349        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2350        editor.end_selection(window, cx);
 2351        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2352
 2353        editor.scroll_manager.show_scrollbars(window, cx);
 2354        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2355
 2356        if full_mode {
 2357            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2358            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2359
 2360            if editor.git_blame_inline_enabled {
 2361                editor.start_git_blame_inline(false, window, cx);
 2362            }
 2363
 2364            editor.go_to_active_debug_line(window, cx);
 2365
 2366            if let Some(buffer) = buffer.read(cx).as_singleton()
 2367                && let Some(project) = editor.project()
 2368            {
 2369                let handle = project.update(cx, |project, cx| {
 2370                    project.register_buffer_with_language_servers(&buffer, cx)
 2371                });
 2372                editor
 2373                    .registered_buffers
 2374                    .insert(buffer.read(cx).remote_id(), handle);
 2375            }
 2376
 2377            editor.minimap =
 2378                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2379            editor.colors = Some(LspColorData::new(cx));
 2380            editor.update_lsp_data(false, None, window, cx);
 2381        }
 2382
 2383        if editor.mode.is_full() {
 2384            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2385        }
 2386
 2387        editor
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending_anchor()
 2416            .is_some_and(|pending_selection| {
 2417                let snapshot = self.buffer().read(cx).snapshot(cx);
 2418                pending_selection.range().includes(range, &snapshot)
 2419            })
 2420        {
 2421            return true;
 2422        }
 2423
 2424        self.selections
 2425            .disjoint_in_range::<usize>(range.clone(), cx)
 2426            .into_iter()
 2427            .any(|selection| {
 2428                // This is needed to cover a corner case, if we just check for an existing
 2429                // selection in the fold range, having a cursor at the start of the fold
 2430                // marks it as selected. Non-empty selections don't cause this.
 2431                let length = selection.end - selection.start;
 2432                length > 0
 2433            })
 2434    }
 2435
 2436    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2437        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2438    }
 2439
 2440    fn key_context_internal(
 2441        &self,
 2442        has_active_edit_prediction: bool,
 2443        window: &Window,
 2444        cx: &App,
 2445    ) -> KeyContext {
 2446        let mut key_context = KeyContext::new_with_defaults();
 2447        key_context.add("Editor");
 2448        let mode = match self.mode {
 2449            EditorMode::SingleLine => "single_line",
 2450            EditorMode::AutoHeight { .. } => "auto_height",
 2451            EditorMode::Minimap { .. } => "minimap",
 2452            EditorMode::Full { .. } => "full",
 2453        };
 2454
 2455        if EditorSettings::jupyter_enabled(cx) {
 2456            key_context.add("jupyter");
 2457        }
 2458
 2459        key_context.set("mode", mode);
 2460        if self.pending_rename.is_some() {
 2461            key_context.add("renaming");
 2462        }
 2463
 2464        match self.context_menu.borrow().as_ref() {
 2465            Some(CodeContextMenu::Completions(menu)) => {
 2466                if menu.visible() {
 2467                    key_context.add("menu");
 2468                    key_context.add("showing_completions");
 2469                }
 2470            }
 2471            Some(CodeContextMenu::CodeActions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_code_actions")
 2475                }
 2476            }
 2477            None => {}
 2478        }
 2479
 2480        if self.signature_help_state.has_multiple_signatures() {
 2481            key_context.add("showing_signature_help");
 2482        }
 2483
 2484        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2485        if !self.focus_handle(cx).contains_focused(window, cx)
 2486            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2487        {
 2488            for addon in self.addons.values() {
 2489                addon.extend_key_context(&mut key_context, cx)
 2490            }
 2491        }
 2492
 2493        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2494            if let Some(extension) = singleton_buffer
 2495                .read(cx)
 2496                .file()
 2497                .and_then(|file| file.path().extension()?.to_str())
 2498            {
 2499                key_context.set("extension", extension.to_string());
 2500            }
 2501        } else {
 2502            key_context.add("multibuffer");
 2503        }
 2504
 2505        if has_active_edit_prediction {
 2506            if self.edit_prediction_in_conflict() {
 2507                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2508            } else {
 2509                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2510                key_context.add("copilot_suggestion");
 2511            }
 2512        }
 2513
 2514        if self.selection_mark_mode {
 2515            key_context.add("selection_mode");
 2516        }
 2517
 2518        key_context
 2519    }
 2520
 2521    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2522        if self.mouse_cursor_hidden {
 2523            self.mouse_cursor_hidden = false;
 2524            cx.notify();
 2525        }
 2526    }
 2527
 2528    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2529        let hide_mouse_cursor = match origin {
 2530            HideMouseCursorOrigin::TypingAction => {
 2531                matches!(
 2532                    self.hide_mouse_mode,
 2533                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2534                )
 2535            }
 2536            HideMouseCursorOrigin::MovementAction => {
 2537                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2538            }
 2539        };
 2540        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2541            self.mouse_cursor_hidden = hide_mouse_cursor;
 2542            cx.notify();
 2543        }
 2544    }
 2545
 2546    pub fn edit_prediction_in_conflict(&self) -> bool {
 2547        if !self.show_edit_predictions_in_menu() {
 2548            return false;
 2549        }
 2550
 2551        let showing_completions = self
 2552            .context_menu
 2553            .borrow()
 2554            .as_ref()
 2555            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2556
 2557        showing_completions
 2558            || self.edit_prediction_requires_modifier()
 2559            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2560            // bindings to insert tab characters.
 2561            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2562    }
 2563
 2564    pub fn accept_edit_prediction_keybind(
 2565        &self,
 2566        accept_partial: bool,
 2567        window: &Window,
 2568        cx: &App,
 2569    ) -> AcceptEditPredictionBinding {
 2570        let key_context = self.key_context_internal(true, window, cx);
 2571        let in_conflict = self.edit_prediction_in_conflict();
 2572
 2573        let bindings = if accept_partial {
 2574            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2575        } else {
 2576            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2577        };
 2578
 2579        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2580        // just the first one.
 2581        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2582            !in_conflict
 2583                || binding
 2584                    .keystrokes()
 2585                    .first()
 2586                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2587        }))
 2588    }
 2589
 2590    pub fn new_file(
 2591        workspace: &mut Workspace,
 2592        _: &workspace::NewFile,
 2593        window: &mut Window,
 2594        cx: &mut Context<Workspace>,
 2595    ) {
 2596        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2597            "Failed to create buffer",
 2598            window,
 2599            cx,
 2600            |e, _, _| match e.error_code() {
 2601                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2602                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2603                e.error_tag("required").unwrap_or("the latest version")
 2604            )),
 2605                _ => None,
 2606            },
 2607        );
 2608    }
 2609
 2610    pub fn new_in_workspace(
 2611        workspace: &mut Workspace,
 2612        window: &mut Window,
 2613        cx: &mut Context<Workspace>,
 2614    ) -> Task<Result<Entity<Editor>>> {
 2615        let project = workspace.project().clone();
 2616        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2617
 2618        cx.spawn_in(window, async move |workspace, cx| {
 2619            let buffer = create.await?;
 2620            workspace.update_in(cx, |workspace, window, cx| {
 2621                let editor =
 2622                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2623                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2624                editor
 2625            })
 2626        })
 2627    }
 2628
 2629    fn new_file_vertical(
 2630        workspace: &mut Workspace,
 2631        _: &workspace::NewFileSplitVertical,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) {
 2635        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2636    }
 2637
 2638    fn new_file_horizontal(
 2639        workspace: &mut Workspace,
 2640        _: &workspace::NewFileSplitHorizontal,
 2641        window: &mut Window,
 2642        cx: &mut Context<Workspace>,
 2643    ) {
 2644        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2645    }
 2646
 2647    fn new_file_in_direction(
 2648        workspace: &mut Workspace,
 2649        direction: SplitDirection,
 2650        window: &mut Window,
 2651        cx: &mut Context<Workspace>,
 2652    ) {
 2653        let project = workspace.project().clone();
 2654        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2655
 2656        cx.spawn_in(window, async move |workspace, cx| {
 2657            let buffer = create.await?;
 2658            workspace.update_in(cx, move |workspace, window, cx| {
 2659                workspace.split_item(
 2660                    direction,
 2661                    Box::new(
 2662                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2663                    ),
 2664                    window,
 2665                    cx,
 2666                )
 2667            })?;
 2668            anyhow::Ok(())
 2669        })
 2670        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2671            match e.error_code() {
 2672                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2673                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2674                e.error_tag("required").unwrap_or("the latest version")
 2675            )),
 2676                _ => None,
 2677            }
 2678        });
 2679    }
 2680
 2681    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2682        self.leader_id
 2683    }
 2684
 2685    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2686        &self.buffer
 2687    }
 2688
 2689    pub fn project(&self) -> Option<&Entity<Project>> {
 2690        self.project.as_ref()
 2691    }
 2692
 2693    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2694        self.workspace.as_ref()?.0.upgrade()
 2695    }
 2696
 2697    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2698        self.buffer().read(cx).title(cx)
 2699    }
 2700
 2701    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2702        let git_blame_gutter_max_author_length = self
 2703            .render_git_blame_gutter(cx)
 2704            .then(|| {
 2705                if let Some(blame) = self.blame.as_ref() {
 2706                    let max_author_length =
 2707                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2708                    Some(max_author_length)
 2709                } else {
 2710                    None
 2711                }
 2712            })
 2713            .flatten();
 2714
 2715        EditorSnapshot {
 2716            mode: self.mode.clone(),
 2717            show_gutter: self.show_gutter,
 2718            show_line_numbers: self.show_line_numbers,
 2719            show_git_diff_gutter: self.show_git_diff_gutter,
 2720            show_code_actions: self.show_code_actions,
 2721            show_runnables: self.show_runnables,
 2722            show_breakpoints: self.show_breakpoints,
 2723            git_blame_gutter_max_author_length,
 2724            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2725            placeholder_display_snapshot: self
 2726                .placeholder_display_map
 2727                .as_ref()
 2728                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2729            scroll_anchor: self.scroll_manager.anchor(),
 2730            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2731            is_focused: self.focus_handle.is_focused(window),
 2732            current_line_highlight: self
 2733                .current_line_highlight
 2734                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2735            gutter_hovered: self.gutter_hovered,
 2736        }
 2737    }
 2738
 2739    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2740        self.buffer.read(cx).language_at(point, cx)
 2741    }
 2742
 2743    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2744        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2745    }
 2746
 2747    pub fn active_excerpt(
 2748        &self,
 2749        cx: &App,
 2750    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2751        self.buffer
 2752            .read(cx)
 2753            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2754    }
 2755
 2756    pub fn mode(&self) -> &EditorMode {
 2757        &self.mode
 2758    }
 2759
 2760    pub fn set_mode(&mut self, mode: EditorMode) {
 2761        self.mode = mode;
 2762    }
 2763
 2764    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2765        self.collaboration_hub.as_deref()
 2766    }
 2767
 2768    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2769        self.collaboration_hub = Some(hub);
 2770    }
 2771
 2772    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2773        self.in_project_search = in_project_search;
 2774    }
 2775
 2776    pub fn set_custom_context_menu(
 2777        &mut self,
 2778        f: impl 'static
 2779        + Fn(
 2780            &mut Self,
 2781            DisplayPoint,
 2782            &mut Window,
 2783            &mut Context<Self>,
 2784        ) -> Option<Entity<ui::ContextMenu>>,
 2785    ) {
 2786        self.custom_context_menu = Some(Box::new(f))
 2787    }
 2788
 2789    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2790        self.completion_provider = provider;
 2791    }
 2792
 2793    #[cfg(any(test, feature = "test-support"))]
 2794    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2795        self.completion_provider.clone()
 2796    }
 2797
 2798    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2799        self.semantics_provider.clone()
 2800    }
 2801
 2802    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2803        self.semantics_provider = provider;
 2804    }
 2805
 2806    pub fn set_edit_prediction_provider<T>(
 2807        &mut self,
 2808        provider: Option<Entity<T>>,
 2809        window: &mut Window,
 2810        cx: &mut Context<Self>,
 2811    ) where
 2812        T: EditPredictionProvider,
 2813    {
 2814        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2815            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2816                if this.focus_handle.is_focused(window) {
 2817                    this.update_visible_edit_prediction(window, cx);
 2818                }
 2819            }),
 2820            provider: Arc::new(provider),
 2821        });
 2822        self.update_edit_prediction_settings(cx);
 2823        self.refresh_edit_prediction(false, false, window, cx);
 2824    }
 2825
 2826    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2827        self.placeholder_display_map
 2828            .as_ref()
 2829            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2830    }
 2831
 2832    pub fn set_placeholder_text(
 2833        &mut self,
 2834        placeholder_text: &str,
 2835        window: &mut Window,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        let multibuffer = cx
 2839            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2840
 2841        let style = window.text_style();
 2842
 2843        self.placeholder_display_map = Some(cx.new(|cx| {
 2844            DisplayMap::new(
 2845                multibuffer,
 2846                style.font(),
 2847                style.font_size.to_pixels(window.rem_size()),
 2848                None,
 2849                FILE_HEADER_HEIGHT,
 2850                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2851                Default::default(),
 2852                DiagnosticSeverity::Off,
 2853                cx,
 2854            )
 2855        }));
 2856        cx.notify();
 2857    }
 2858
 2859    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2860        self.cursor_shape = cursor_shape;
 2861
 2862        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2863        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2864
 2865        cx.notify();
 2866    }
 2867
 2868    pub fn set_current_line_highlight(
 2869        &mut self,
 2870        current_line_highlight: Option<CurrentLineHighlight>,
 2871    ) {
 2872        self.current_line_highlight = current_line_highlight;
 2873    }
 2874
 2875    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2876        self.collapse_matches = collapse_matches;
 2877    }
 2878
 2879    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2880        let buffers = self.buffer.read(cx).all_buffers();
 2881        let Some(project) = self.project.as_ref() else {
 2882            return;
 2883        };
 2884        project.update(cx, |project, cx| {
 2885            for buffer in buffers {
 2886                self.registered_buffers
 2887                    .entry(buffer.read(cx).remote_id())
 2888                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2889            }
 2890        })
 2891    }
 2892
 2893    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2894        if self.collapse_matches {
 2895            return range.start..range.start;
 2896        }
 2897        range.clone()
 2898    }
 2899
 2900    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2901        if self.display_map.read(cx).clip_at_line_ends != clip {
 2902            self.display_map
 2903                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2904        }
 2905    }
 2906
 2907    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2908        self.input_enabled = input_enabled;
 2909    }
 2910
 2911    pub fn set_edit_predictions_hidden_for_vim_mode(
 2912        &mut self,
 2913        hidden: bool,
 2914        window: &mut Window,
 2915        cx: &mut Context<Self>,
 2916    ) {
 2917        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2918            self.edit_predictions_hidden_for_vim_mode = hidden;
 2919            if hidden {
 2920                self.update_visible_edit_prediction(window, cx);
 2921            } else {
 2922                self.refresh_edit_prediction(true, false, window, cx);
 2923            }
 2924        }
 2925    }
 2926
 2927    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2928        self.menu_edit_predictions_policy = value;
 2929    }
 2930
 2931    pub fn set_autoindent(&mut self, autoindent: bool) {
 2932        if autoindent {
 2933            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2934        } else {
 2935            self.autoindent_mode = None;
 2936        }
 2937    }
 2938
 2939    pub fn read_only(&self, cx: &App) -> bool {
 2940        self.read_only || self.buffer.read(cx).read_only()
 2941    }
 2942
 2943    pub fn set_read_only(&mut self, read_only: bool) {
 2944        self.read_only = read_only;
 2945    }
 2946
 2947    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2948        self.use_autoclose = autoclose;
 2949    }
 2950
 2951    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2952        self.use_auto_surround = auto_surround;
 2953    }
 2954
 2955    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2956        self.auto_replace_emoji_shortcode = auto_replace;
 2957    }
 2958
 2959    pub fn toggle_edit_predictions(
 2960        &mut self,
 2961        _: &ToggleEditPrediction,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        if self.show_edit_predictions_override.is_some() {
 2966            self.set_show_edit_predictions(None, window, cx);
 2967        } else {
 2968            let show_edit_predictions = !self.edit_predictions_enabled();
 2969            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2970        }
 2971    }
 2972
 2973    pub fn set_show_edit_predictions(
 2974        &mut self,
 2975        show_edit_predictions: Option<bool>,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        self.show_edit_predictions_override = show_edit_predictions;
 2980        self.update_edit_prediction_settings(cx);
 2981
 2982        if let Some(false) = show_edit_predictions {
 2983            self.discard_edit_prediction(false, cx);
 2984        } else {
 2985            self.refresh_edit_prediction(false, true, window, cx);
 2986        }
 2987    }
 2988
 2989    fn edit_predictions_disabled_in_scope(
 2990        &self,
 2991        buffer: &Entity<Buffer>,
 2992        buffer_position: language::Anchor,
 2993        cx: &App,
 2994    ) -> bool {
 2995        let snapshot = buffer.read(cx).snapshot();
 2996        let settings = snapshot.settings_at(buffer_position, cx);
 2997
 2998        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2999            return false;
 3000        };
 3001
 3002        scope.override_name().is_some_and(|scope_name| {
 3003            settings
 3004                .edit_predictions_disabled_in
 3005                .iter()
 3006                .any(|s| s == scope_name)
 3007        })
 3008    }
 3009
 3010    pub fn set_use_modal_editing(&mut self, to: bool) {
 3011        self.use_modal_editing = to;
 3012    }
 3013
 3014    pub fn use_modal_editing(&self) -> bool {
 3015        self.use_modal_editing
 3016    }
 3017
 3018    fn selections_did_change(
 3019        &mut self,
 3020        local: bool,
 3021        old_cursor_position: &Anchor,
 3022        effects: SelectionEffects,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        window.invalidate_character_coordinates();
 3027
 3028        // Copy selections to primary selection buffer
 3029        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3030        if local {
 3031            let selections = self.selections.all::<usize>(cx);
 3032            let buffer_handle = self.buffer.read(cx).read(cx);
 3033
 3034            let mut text = String::new();
 3035            for (index, selection) in selections.iter().enumerate() {
 3036                let text_for_selection = buffer_handle
 3037                    .text_for_range(selection.start..selection.end)
 3038                    .collect::<String>();
 3039
 3040                text.push_str(&text_for_selection);
 3041                if index != selections.len() - 1 {
 3042                    text.push('\n');
 3043                }
 3044            }
 3045
 3046            if !text.is_empty() {
 3047                cx.write_to_primary(ClipboardItem::new_string(text));
 3048            }
 3049        }
 3050
 3051        let selection_anchors = self.selections.disjoint_anchors_arc();
 3052
 3053        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3054            self.buffer.update(cx, |buffer, cx| {
 3055                buffer.set_active_selections(
 3056                    &selection_anchors,
 3057                    self.selections.line_mode,
 3058                    self.cursor_shape,
 3059                    cx,
 3060                )
 3061            });
 3062        }
 3063        let display_map = self
 3064            .display_map
 3065            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3066        let buffer = &display_map.buffer_snapshot;
 3067        if self.selections.count() == 1 {
 3068            self.add_selections_state = None;
 3069        }
 3070        self.select_next_state = None;
 3071        self.select_prev_state = None;
 3072        self.select_syntax_node_history.try_clear();
 3073        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3074        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3075        self.take_rename(false, window, cx);
 3076
 3077        let newest_selection = self.selections.newest_anchor();
 3078        let new_cursor_position = newest_selection.head();
 3079        let selection_start = newest_selection.start;
 3080
 3081        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3082            self.push_to_nav_history(
 3083                *old_cursor_position,
 3084                Some(new_cursor_position.to_point(buffer)),
 3085                false,
 3086                effects.nav_history == Some(true),
 3087                cx,
 3088            );
 3089        }
 3090
 3091        if local {
 3092            if let Some(buffer_id) = new_cursor_position.buffer_id
 3093                && !self.registered_buffers.contains_key(&buffer_id)
 3094                && let Some(project) = self.project.as_ref()
 3095            {
 3096                project.update(cx, |project, cx| {
 3097                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3098                        return;
 3099                    };
 3100                    self.registered_buffers.insert(
 3101                        buffer_id,
 3102                        project.register_buffer_with_language_servers(&buffer, cx),
 3103                    );
 3104                })
 3105            }
 3106
 3107            let mut context_menu = self.context_menu.borrow_mut();
 3108            let completion_menu = match context_menu.as_ref() {
 3109                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3110                Some(CodeContextMenu::CodeActions(_)) => {
 3111                    *context_menu = None;
 3112                    None
 3113                }
 3114                None => None,
 3115            };
 3116            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3117            drop(context_menu);
 3118
 3119            if effects.completions
 3120                && let Some(completion_position) = completion_position
 3121            {
 3122                let start_offset = selection_start.to_offset(buffer);
 3123                let position_matches = start_offset == completion_position.to_offset(buffer);
 3124                let continue_showing = if position_matches {
 3125                    if self.snippet_stack.is_empty() {
 3126                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3127                            == Some(CharKind::Word)
 3128                    } else {
 3129                        // Snippet choices can be shown even when the cursor is in whitespace.
 3130                        // Dismissing the menu with actions like backspace is handled by
 3131                        // invalidation regions.
 3132                        true
 3133                    }
 3134                } else {
 3135                    false
 3136                };
 3137
 3138                if continue_showing {
 3139                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3140                } else {
 3141                    self.hide_context_menu(window, cx);
 3142                }
 3143            }
 3144
 3145            hide_hover(self, cx);
 3146
 3147            if old_cursor_position.to_display_point(&display_map).row()
 3148                != new_cursor_position.to_display_point(&display_map).row()
 3149            {
 3150                self.available_code_actions.take();
 3151            }
 3152            self.refresh_code_actions(window, cx);
 3153            self.refresh_document_highlights(cx);
 3154            self.refresh_selected_text_highlights(false, window, cx);
 3155            refresh_matching_bracket_highlights(self, window, cx);
 3156            self.update_visible_edit_prediction(window, cx);
 3157            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3158            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3159            self.inline_blame_popover.take();
 3160            if self.git_blame_inline_enabled {
 3161                self.start_inline_blame_timer(window, cx);
 3162            }
 3163        }
 3164
 3165        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3166        cx.emit(EditorEvent::SelectionsChanged { local });
 3167
 3168        let selections = &self.selections.disjoint_anchors_arc();
 3169        if selections.len() == 1 {
 3170            cx.emit(SearchEvent::ActiveMatchChanged)
 3171        }
 3172        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3173            let inmemory_selections = selections
 3174                .iter()
 3175                .map(|s| {
 3176                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3177                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3178                })
 3179                .collect();
 3180            self.update_restoration_data(cx, |data| {
 3181                data.selections = inmemory_selections;
 3182            });
 3183
 3184            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3185                && let Some(workspace_id) =
 3186                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3187            {
 3188                let snapshot = self.buffer().read(cx).snapshot(cx);
 3189                let selections = selections.clone();
 3190                let background_executor = cx.background_executor().clone();
 3191                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3192                self.serialize_selections = cx.background_spawn(async move {
 3193                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3194                            let db_selections = selections
 3195                                .iter()
 3196                                .map(|selection| {
 3197                                    (
 3198                                        selection.start.to_offset(&snapshot),
 3199                                        selection.end.to_offset(&snapshot),
 3200                                    )
 3201                                })
 3202                                .collect();
 3203
 3204                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3205                                .await
 3206                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3207                                .log_err();
 3208                        });
 3209            }
 3210        }
 3211
 3212        cx.notify();
 3213    }
 3214
 3215    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3216        use text::ToOffset as _;
 3217        use text::ToPoint as _;
 3218
 3219        if self.mode.is_minimap()
 3220            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3221        {
 3222            return;
 3223        }
 3224
 3225        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3226            return;
 3227        };
 3228
 3229        let snapshot = singleton.read(cx).snapshot();
 3230        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3231            let display_snapshot = display_map.snapshot(cx);
 3232
 3233            display_snapshot
 3234                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3235                .map(|fold| {
 3236                    fold.range.start.text_anchor.to_point(&snapshot)
 3237                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3238                })
 3239                .collect()
 3240        });
 3241        self.update_restoration_data(cx, |data| {
 3242            data.folds = inmemory_folds;
 3243        });
 3244
 3245        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3246            return;
 3247        };
 3248        let background_executor = cx.background_executor().clone();
 3249        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3250        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3251            display_map
 3252                .snapshot(cx)
 3253                .folds_in_range(0..snapshot.len())
 3254                .map(|fold| {
 3255                    (
 3256                        fold.range.start.text_anchor.to_offset(&snapshot),
 3257                        fold.range.end.text_anchor.to_offset(&snapshot),
 3258                    )
 3259                })
 3260                .collect()
 3261        });
 3262        self.serialize_folds = cx.background_spawn(async move {
 3263            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3264            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3265                .await
 3266                .with_context(|| {
 3267                    format!(
 3268                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3269                    )
 3270                })
 3271                .log_err();
 3272        });
 3273    }
 3274
 3275    pub fn sync_selections(
 3276        &mut self,
 3277        other: Entity<Editor>,
 3278        cx: &mut Context<Self>,
 3279    ) -> gpui::Subscription {
 3280        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3281        self.selections.change_with(cx, |selections| {
 3282            selections.select_anchors(other_selections);
 3283        });
 3284
 3285        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3286            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3287                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3288                if other_selections.is_empty() {
 3289                    return;
 3290                }
 3291                this.selections.change_with(cx, |selections| {
 3292                    selections.select_anchors(other_selections);
 3293                });
 3294            }
 3295        });
 3296
 3297        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3298            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3299                let these_selections = this.selections.disjoint_anchors().to_vec();
 3300                if these_selections.is_empty() {
 3301                    return;
 3302                }
 3303                other.update(cx, |other_editor, cx| {
 3304                    other_editor.selections.change_with(cx, |selections| {
 3305                        selections.select_anchors(these_selections);
 3306                    })
 3307                });
 3308            }
 3309        });
 3310
 3311        Subscription::join(other_subscription, this_subscription)
 3312    }
 3313
 3314    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3315    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3316    /// effects of selection change occur at the end of the transaction.
 3317    pub fn change_selections<R>(
 3318        &mut self,
 3319        effects: SelectionEffects,
 3320        window: &mut Window,
 3321        cx: &mut Context<Self>,
 3322        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3323    ) -> R {
 3324        if let Some(state) = &mut self.deferred_selection_effects_state {
 3325            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3326            state.effects.completions = effects.completions;
 3327            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3328            let (changed, result) = self.selections.change_with(cx, change);
 3329            state.changed |= changed;
 3330            return result;
 3331        }
 3332        let mut state = DeferredSelectionEffectsState {
 3333            changed: false,
 3334            effects,
 3335            old_cursor_position: self.selections.newest_anchor().head(),
 3336            history_entry: SelectionHistoryEntry {
 3337                selections: self.selections.disjoint_anchors_arc(),
 3338                select_next_state: self.select_next_state.clone(),
 3339                select_prev_state: self.select_prev_state.clone(),
 3340                add_selections_state: self.add_selections_state.clone(),
 3341            },
 3342        };
 3343        let (changed, result) = self.selections.change_with(cx, change);
 3344        state.changed = state.changed || changed;
 3345        if self.defer_selection_effects {
 3346            self.deferred_selection_effects_state = Some(state);
 3347        } else {
 3348            self.apply_selection_effects(state, window, cx);
 3349        }
 3350        result
 3351    }
 3352
 3353    /// Defers the effects of selection change, so that the effects of multiple calls to
 3354    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3355    /// to selection history and the state of popovers based on selection position aren't
 3356    /// erroneously updated.
 3357    pub fn with_selection_effects_deferred<R>(
 3358        &mut self,
 3359        window: &mut Window,
 3360        cx: &mut Context<Self>,
 3361        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3362    ) -> R {
 3363        let already_deferred = self.defer_selection_effects;
 3364        self.defer_selection_effects = true;
 3365        let result = update(self, window, cx);
 3366        if !already_deferred {
 3367            self.defer_selection_effects = false;
 3368            if let Some(state) = self.deferred_selection_effects_state.take() {
 3369                self.apply_selection_effects(state, window, cx);
 3370            }
 3371        }
 3372        result
 3373    }
 3374
 3375    fn apply_selection_effects(
 3376        &mut self,
 3377        state: DeferredSelectionEffectsState,
 3378        window: &mut Window,
 3379        cx: &mut Context<Self>,
 3380    ) {
 3381        if state.changed {
 3382            self.selection_history.push(state.history_entry);
 3383
 3384            if let Some(autoscroll) = state.effects.scroll {
 3385                self.request_autoscroll(autoscroll, cx);
 3386            }
 3387
 3388            let old_cursor_position = &state.old_cursor_position;
 3389
 3390            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3391
 3392            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3393                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3394            }
 3395        }
 3396    }
 3397
 3398    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3399    where
 3400        I: IntoIterator<Item = (Range<S>, T)>,
 3401        S: ToOffset,
 3402        T: Into<Arc<str>>,
 3403    {
 3404        if self.read_only(cx) {
 3405            return;
 3406        }
 3407
 3408        self.buffer
 3409            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3410    }
 3411
 3412    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3413    where
 3414        I: IntoIterator<Item = (Range<S>, T)>,
 3415        S: ToOffset,
 3416        T: Into<Arc<str>>,
 3417    {
 3418        if self.read_only(cx) {
 3419            return;
 3420        }
 3421
 3422        self.buffer.update(cx, |buffer, cx| {
 3423            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3424        });
 3425    }
 3426
 3427    pub fn edit_with_block_indent<I, S, T>(
 3428        &mut self,
 3429        edits: I,
 3430        original_indent_columns: Vec<Option<u32>>,
 3431        cx: &mut Context<Self>,
 3432    ) where
 3433        I: IntoIterator<Item = (Range<S>, T)>,
 3434        S: ToOffset,
 3435        T: Into<Arc<str>>,
 3436    {
 3437        if self.read_only(cx) {
 3438            return;
 3439        }
 3440
 3441        self.buffer.update(cx, |buffer, cx| {
 3442            buffer.edit(
 3443                edits,
 3444                Some(AutoindentMode::Block {
 3445                    original_indent_columns,
 3446                }),
 3447                cx,
 3448            )
 3449        });
 3450    }
 3451
 3452    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3453        self.hide_context_menu(window, cx);
 3454
 3455        match phase {
 3456            SelectPhase::Begin {
 3457                position,
 3458                add,
 3459                click_count,
 3460            } => self.begin_selection(position, add, click_count, window, cx),
 3461            SelectPhase::BeginColumnar {
 3462                position,
 3463                goal_column,
 3464                reset,
 3465                mode,
 3466            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3467            SelectPhase::Extend {
 3468                position,
 3469                click_count,
 3470            } => self.extend_selection(position, click_count, window, cx),
 3471            SelectPhase::Update {
 3472                position,
 3473                goal_column,
 3474                scroll_delta,
 3475            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3476            SelectPhase::End => self.end_selection(window, cx),
 3477        }
 3478    }
 3479
 3480    fn extend_selection(
 3481        &mut self,
 3482        position: DisplayPoint,
 3483        click_count: usize,
 3484        window: &mut Window,
 3485        cx: &mut Context<Self>,
 3486    ) {
 3487        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3488        let tail = self.selections.newest::<usize>(cx).tail();
 3489        self.begin_selection(position, false, click_count, window, cx);
 3490
 3491        let position = position.to_offset(&display_map, Bias::Left);
 3492        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3493
 3494        let mut pending_selection = self
 3495            .selections
 3496            .pending_anchor()
 3497            .cloned()
 3498            .expect("extend_selection not called with pending selection");
 3499        if position >= tail {
 3500            pending_selection.start = tail_anchor;
 3501        } else {
 3502            pending_selection.end = tail_anchor;
 3503            pending_selection.reversed = true;
 3504        }
 3505
 3506        let mut pending_mode = self.selections.pending_mode().unwrap();
 3507        match &mut pending_mode {
 3508            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3509            _ => {}
 3510        }
 3511
 3512        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3513            SelectionEffects::scroll(Autoscroll::fit())
 3514        } else {
 3515            SelectionEffects::no_scroll()
 3516        };
 3517
 3518        self.change_selections(effects, window, cx, |s| {
 3519            s.set_pending(pending_selection.clone(), pending_mode)
 3520        });
 3521    }
 3522
 3523    fn begin_selection(
 3524        &mut self,
 3525        position: DisplayPoint,
 3526        add: bool,
 3527        click_count: usize,
 3528        window: &mut Window,
 3529        cx: &mut Context<Self>,
 3530    ) {
 3531        if !self.focus_handle.is_focused(window) {
 3532            self.last_focused_descendant = None;
 3533            window.focus(&self.focus_handle);
 3534        }
 3535
 3536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3537        let buffer = &display_map.buffer_snapshot;
 3538        let position = display_map.clip_point(position, Bias::Left);
 3539
 3540        let start;
 3541        let end;
 3542        let mode;
 3543        let mut auto_scroll;
 3544        match click_count {
 3545            1 => {
 3546                start = buffer.anchor_before(position.to_point(&display_map));
 3547                end = start;
 3548                mode = SelectMode::Character;
 3549                auto_scroll = true;
 3550            }
 3551            2 => {
 3552                let position = display_map
 3553                    .clip_point(position, Bias::Left)
 3554                    .to_offset(&display_map, Bias::Left);
 3555                let (range, _) = buffer.surrounding_word(position, None);
 3556                start = buffer.anchor_before(range.start);
 3557                end = buffer.anchor_before(range.end);
 3558                mode = SelectMode::Word(start..end);
 3559                auto_scroll = true;
 3560            }
 3561            3 => {
 3562                let position = display_map
 3563                    .clip_point(position, Bias::Left)
 3564                    .to_point(&display_map);
 3565                let line_start = display_map.prev_line_boundary(position).0;
 3566                let next_line_start = buffer.clip_point(
 3567                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3568                    Bias::Left,
 3569                );
 3570                start = buffer.anchor_before(line_start);
 3571                end = buffer.anchor_before(next_line_start);
 3572                mode = SelectMode::Line(start..end);
 3573                auto_scroll = true;
 3574            }
 3575            _ => {
 3576                start = buffer.anchor_before(0);
 3577                end = buffer.anchor_before(buffer.len());
 3578                mode = SelectMode::All;
 3579                auto_scroll = false;
 3580            }
 3581        }
 3582        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3583
 3584        let point_to_delete: Option<usize> = {
 3585            let selected_points: Vec<Selection<Point>> =
 3586                self.selections.disjoint_in_range(start..end, cx);
 3587
 3588            if !add || click_count > 1 {
 3589                None
 3590            } else if !selected_points.is_empty() {
 3591                Some(selected_points[0].id)
 3592            } else {
 3593                let clicked_point_already_selected =
 3594                    self.selections.disjoint_anchors().iter().find(|selection| {
 3595                        selection.start.to_point(buffer) == start.to_point(buffer)
 3596                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3597                    });
 3598
 3599                clicked_point_already_selected.map(|selection| selection.id)
 3600            }
 3601        };
 3602
 3603        let selections_count = self.selections.count();
 3604        let effects = if auto_scroll {
 3605            SelectionEffects::default()
 3606        } else {
 3607            SelectionEffects::no_scroll()
 3608        };
 3609
 3610        self.change_selections(effects, window, cx, |s| {
 3611            if let Some(point_to_delete) = point_to_delete {
 3612                s.delete(point_to_delete);
 3613
 3614                if selections_count == 1 {
 3615                    s.set_pending_anchor_range(start..end, mode);
 3616                }
 3617            } else {
 3618                if !add {
 3619                    s.clear_disjoint();
 3620                }
 3621
 3622                s.set_pending_anchor_range(start..end, mode);
 3623            }
 3624        });
 3625    }
 3626
 3627    fn begin_columnar_selection(
 3628        &mut self,
 3629        position: DisplayPoint,
 3630        goal_column: u32,
 3631        reset: bool,
 3632        mode: ColumnarMode,
 3633        window: &mut Window,
 3634        cx: &mut Context<Self>,
 3635    ) {
 3636        if !self.focus_handle.is_focused(window) {
 3637            self.last_focused_descendant = None;
 3638            window.focus(&self.focus_handle);
 3639        }
 3640
 3641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3642
 3643        if reset {
 3644            let pointer_position = display_map
 3645                .buffer_snapshot
 3646                .anchor_before(position.to_point(&display_map));
 3647
 3648            self.change_selections(
 3649                SelectionEffects::scroll(Autoscroll::newest()),
 3650                window,
 3651                cx,
 3652                |s| {
 3653                    s.clear_disjoint();
 3654                    s.set_pending_anchor_range(
 3655                        pointer_position..pointer_position,
 3656                        SelectMode::Character,
 3657                    );
 3658                },
 3659            );
 3660        };
 3661
 3662        let tail = self.selections.newest::<Point>(cx).tail();
 3663        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3664        self.columnar_selection_state = match mode {
 3665            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3666                selection_tail: selection_anchor,
 3667                display_point: if reset {
 3668                    if position.column() != goal_column {
 3669                        Some(DisplayPoint::new(position.row(), goal_column))
 3670                    } else {
 3671                        None
 3672                    }
 3673                } else {
 3674                    None
 3675                },
 3676            }),
 3677            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3678                selection_tail: selection_anchor,
 3679            }),
 3680        };
 3681
 3682        if !reset {
 3683            self.select_columns(position, goal_column, &display_map, window, cx);
 3684        }
 3685    }
 3686
 3687    fn update_selection(
 3688        &mut self,
 3689        position: DisplayPoint,
 3690        goal_column: u32,
 3691        scroll_delta: gpui::Point<f32>,
 3692        window: &mut Window,
 3693        cx: &mut Context<Self>,
 3694    ) {
 3695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3696
 3697        if self.columnar_selection_state.is_some() {
 3698            self.select_columns(position, goal_column, &display_map, window, cx);
 3699        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3700            let buffer = &display_map.buffer_snapshot;
 3701            let head;
 3702            let tail;
 3703            let mode = self.selections.pending_mode().unwrap();
 3704            match &mode {
 3705                SelectMode::Character => {
 3706                    head = position.to_point(&display_map);
 3707                    tail = pending.tail().to_point(buffer);
 3708                }
 3709                SelectMode::Word(original_range) => {
 3710                    let offset = display_map
 3711                        .clip_point(position, Bias::Left)
 3712                        .to_offset(&display_map, Bias::Left);
 3713                    let original_range = original_range.to_offset(buffer);
 3714
 3715                    let head_offset = if buffer.is_inside_word(offset, None)
 3716                        || original_range.contains(&offset)
 3717                    {
 3718                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3719                        if word_range.start < original_range.start {
 3720                            word_range.start
 3721                        } else {
 3722                            word_range.end
 3723                        }
 3724                    } else {
 3725                        offset
 3726                    };
 3727
 3728                    head = head_offset.to_point(buffer);
 3729                    if head_offset <= original_range.start {
 3730                        tail = original_range.end.to_point(buffer);
 3731                    } else {
 3732                        tail = original_range.start.to_point(buffer);
 3733                    }
 3734                }
 3735                SelectMode::Line(original_range) => {
 3736                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3737
 3738                    let position = display_map
 3739                        .clip_point(position, Bias::Left)
 3740                        .to_point(&display_map);
 3741                    let line_start = display_map.prev_line_boundary(position).0;
 3742                    let next_line_start = buffer.clip_point(
 3743                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3744                        Bias::Left,
 3745                    );
 3746
 3747                    if line_start < original_range.start {
 3748                        head = line_start
 3749                    } else {
 3750                        head = next_line_start
 3751                    }
 3752
 3753                    if head <= original_range.start {
 3754                        tail = original_range.end;
 3755                    } else {
 3756                        tail = original_range.start;
 3757                    }
 3758                }
 3759                SelectMode::All => {
 3760                    return;
 3761                }
 3762            };
 3763
 3764            if head < tail {
 3765                pending.start = buffer.anchor_before(head);
 3766                pending.end = buffer.anchor_before(tail);
 3767                pending.reversed = true;
 3768            } else {
 3769                pending.start = buffer.anchor_before(tail);
 3770                pending.end = buffer.anchor_before(head);
 3771                pending.reversed = false;
 3772            }
 3773
 3774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3775                s.set_pending(pending.clone(), mode);
 3776            });
 3777        } else {
 3778            log::error!("update_selection dispatched with no pending selection");
 3779            return;
 3780        }
 3781
 3782        self.apply_scroll_delta(scroll_delta, window, cx);
 3783        cx.notify();
 3784    }
 3785
 3786    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3787        self.columnar_selection_state.take();
 3788        if self.selections.pending_anchor().is_some() {
 3789            let selections = self.selections.all::<usize>(cx);
 3790            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3791                s.select(selections);
 3792                s.clear_pending();
 3793            });
 3794        }
 3795    }
 3796
 3797    fn select_columns(
 3798        &mut self,
 3799        head: DisplayPoint,
 3800        goal_column: u32,
 3801        display_map: &DisplaySnapshot,
 3802        window: &mut Window,
 3803        cx: &mut Context<Self>,
 3804    ) {
 3805        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3806            return;
 3807        };
 3808
 3809        let tail = match columnar_state {
 3810            ColumnarSelectionState::FromMouse {
 3811                selection_tail,
 3812                display_point,
 3813            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3814            ColumnarSelectionState::FromSelection { selection_tail } => {
 3815                selection_tail.to_display_point(display_map)
 3816            }
 3817        };
 3818
 3819        let start_row = cmp::min(tail.row(), head.row());
 3820        let end_row = cmp::max(tail.row(), head.row());
 3821        let start_column = cmp::min(tail.column(), goal_column);
 3822        let end_column = cmp::max(tail.column(), goal_column);
 3823        let reversed = start_column < tail.column();
 3824
 3825        let selection_ranges = (start_row.0..=end_row.0)
 3826            .map(DisplayRow)
 3827            .filter_map(|row| {
 3828                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3829                    || start_column <= display_map.line_len(row))
 3830                    && !display_map.is_block_line(row)
 3831                {
 3832                    let start = display_map
 3833                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3834                        .to_point(display_map);
 3835                    let end = display_map
 3836                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3837                        .to_point(display_map);
 3838                    if reversed {
 3839                        Some(end..start)
 3840                    } else {
 3841                        Some(start..end)
 3842                    }
 3843                } else {
 3844                    None
 3845                }
 3846            })
 3847            .collect::<Vec<_>>();
 3848
 3849        let ranges = match columnar_state {
 3850            ColumnarSelectionState::FromMouse { .. } => {
 3851                let mut non_empty_ranges = selection_ranges
 3852                    .iter()
 3853                    .filter(|selection_range| selection_range.start != selection_range.end)
 3854                    .peekable();
 3855                if non_empty_ranges.peek().is_some() {
 3856                    non_empty_ranges.cloned().collect()
 3857                } else {
 3858                    selection_ranges
 3859                }
 3860            }
 3861            _ => selection_ranges,
 3862        };
 3863
 3864        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3865            s.select_ranges(ranges);
 3866        });
 3867        cx.notify();
 3868    }
 3869
 3870    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3871        self.selections
 3872            .all_adjusted(cx)
 3873            .iter()
 3874            .any(|selection| !selection.is_empty())
 3875    }
 3876
 3877    pub fn has_pending_nonempty_selection(&self) -> bool {
 3878        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3879            Some(Selection { start, end, .. }) => start != end,
 3880            None => false,
 3881        };
 3882
 3883        pending_nonempty_selection
 3884            || (self.columnar_selection_state.is_some()
 3885                && self.selections.disjoint_anchors().len() > 1)
 3886    }
 3887
 3888    pub fn has_pending_selection(&self) -> bool {
 3889        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3890    }
 3891
 3892    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3893        self.selection_mark_mode = false;
 3894        self.selection_drag_state = SelectionDragState::None;
 3895
 3896        if self.clear_expanded_diff_hunks(cx) {
 3897            cx.notify();
 3898            return;
 3899        }
 3900        if self.dismiss_menus_and_popups(true, window, cx) {
 3901            return;
 3902        }
 3903
 3904        if self.mode.is_full()
 3905            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3906        {
 3907            return;
 3908        }
 3909
 3910        cx.propagate();
 3911    }
 3912
 3913    pub fn dismiss_menus_and_popups(
 3914        &mut self,
 3915        is_user_requested: bool,
 3916        window: &mut Window,
 3917        cx: &mut Context<Self>,
 3918    ) -> bool {
 3919        if self.take_rename(false, window, cx).is_some() {
 3920            return true;
 3921        }
 3922
 3923        if hide_hover(self, cx) {
 3924            return true;
 3925        }
 3926
 3927        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3928            return true;
 3929        }
 3930
 3931        if self.hide_context_menu(window, cx).is_some() {
 3932            return true;
 3933        }
 3934
 3935        if self.mouse_context_menu.take().is_some() {
 3936            return true;
 3937        }
 3938
 3939        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3940            return true;
 3941        }
 3942
 3943        if self.snippet_stack.pop().is_some() {
 3944            return true;
 3945        }
 3946
 3947        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3948            self.dismiss_diagnostics(cx);
 3949            return true;
 3950        }
 3951
 3952        false
 3953    }
 3954
 3955    fn linked_editing_ranges_for(
 3956        &self,
 3957        selection: Range<text::Anchor>,
 3958        cx: &App,
 3959    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3960        if self.linked_edit_ranges.is_empty() {
 3961            return None;
 3962        }
 3963        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3964            selection.end.buffer_id.and_then(|end_buffer_id| {
 3965                if selection.start.buffer_id != Some(end_buffer_id) {
 3966                    return None;
 3967                }
 3968                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3969                let snapshot = buffer.read(cx).snapshot();
 3970                self.linked_edit_ranges
 3971                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3972                    .map(|ranges| (ranges, snapshot, buffer))
 3973            })?;
 3974        use text::ToOffset as TO;
 3975        // find offset from the start of current range to current cursor position
 3976        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3977
 3978        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3979        let start_difference = start_offset - start_byte_offset;
 3980        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3981        let end_difference = end_offset - start_byte_offset;
 3982        // Current range has associated linked ranges.
 3983        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3984        for range in linked_ranges.iter() {
 3985            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3986            let end_offset = start_offset + end_difference;
 3987            let start_offset = start_offset + start_difference;
 3988            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3989                continue;
 3990            }
 3991            if self.selections.disjoint_anchor_ranges().any(|s| {
 3992                if s.start.buffer_id != selection.start.buffer_id
 3993                    || s.end.buffer_id != selection.end.buffer_id
 3994                {
 3995                    return false;
 3996                }
 3997                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3998                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3999            }) {
 4000                continue;
 4001            }
 4002            let start = buffer_snapshot.anchor_after(start_offset);
 4003            let end = buffer_snapshot.anchor_after(end_offset);
 4004            linked_edits
 4005                .entry(buffer.clone())
 4006                .or_default()
 4007                .push(start..end);
 4008        }
 4009        Some(linked_edits)
 4010    }
 4011
 4012    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4013        let text: Arc<str> = text.into();
 4014
 4015        if self.read_only(cx) {
 4016            return;
 4017        }
 4018
 4019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4020
 4021        let selections = self.selections.all_adjusted(cx);
 4022        let mut bracket_inserted = false;
 4023        let mut edits = Vec::new();
 4024        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4025        let mut new_selections = Vec::with_capacity(selections.len());
 4026        let mut new_autoclose_regions = Vec::new();
 4027        let snapshot = self.buffer.read(cx).read(cx);
 4028        let mut clear_linked_edit_ranges = false;
 4029
 4030        for (selection, autoclose_region) in
 4031            self.selections_with_autoclose_regions(selections, &snapshot)
 4032        {
 4033            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4034                // Determine if the inserted text matches the opening or closing
 4035                // bracket of any of this language's bracket pairs.
 4036                let mut bracket_pair = None;
 4037                let mut is_bracket_pair_start = false;
 4038                let mut is_bracket_pair_end = false;
 4039                if !text.is_empty() {
 4040                    let mut bracket_pair_matching_end = None;
 4041                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4042                    //  and they are removing the character that triggered IME popup.
 4043                    for (pair, enabled) in scope.brackets() {
 4044                        if !pair.close && !pair.surround {
 4045                            continue;
 4046                        }
 4047
 4048                        if enabled && pair.start.ends_with(text.as_ref()) {
 4049                            let prefix_len = pair.start.len() - text.len();
 4050                            let preceding_text_matches_prefix = prefix_len == 0
 4051                                || (selection.start.column >= (prefix_len as u32)
 4052                                    && snapshot.contains_str_at(
 4053                                        Point::new(
 4054                                            selection.start.row,
 4055                                            selection.start.column - (prefix_len as u32),
 4056                                        ),
 4057                                        &pair.start[..prefix_len],
 4058                                    ));
 4059                            if preceding_text_matches_prefix {
 4060                                bracket_pair = Some(pair.clone());
 4061                                is_bracket_pair_start = true;
 4062                                break;
 4063                            }
 4064                        }
 4065                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4066                        {
 4067                            // take first bracket pair matching end, but don't break in case a later bracket
 4068                            // pair matches start
 4069                            bracket_pair_matching_end = Some(pair.clone());
 4070                        }
 4071                    }
 4072                    if let Some(end) = bracket_pair_matching_end
 4073                        && bracket_pair.is_none()
 4074                    {
 4075                        bracket_pair = Some(end);
 4076                        is_bracket_pair_end = true;
 4077                    }
 4078                }
 4079
 4080                if let Some(bracket_pair) = bracket_pair {
 4081                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4082                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4083                    let auto_surround =
 4084                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4085                    if selection.is_empty() {
 4086                        if is_bracket_pair_start {
 4087                            // If the inserted text is a suffix of an opening bracket and the
 4088                            // selection is preceded by the rest of the opening bracket, then
 4089                            // insert the closing bracket.
 4090                            let following_text_allows_autoclose = snapshot
 4091                                .chars_at(selection.start)
 4092                                .next()
 4093                                .is_none_or(|c| scope.should_autoclose_before(c));
 4094
 4095                            let preceding_text_allows_autoclose = selection.start.column == 0
 4096                                || snapshot
 4097                                    .reversed_chars_at(selection.start)
 4098                                    .next()
 4099                                    .is_none_or(|c| {
 4100                                        bracket_pair.start != bracket_pair.end
 4101                                            || !snapshot
 4102                                                .char_classifier_at(selection.start)
 4103                                                .is_word(c)
 4104                                    });
 4105
 4106                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4107                                && bracket_pair.start.len() == 1
 4108                            {
 4109                                let target = bracket_pair.start.chars().next().unwrap();
 4110                                let current_line_count = snapshot
 4111                                    .reversed_chars_at(selection.start)
 4112                                    .take_while(|&c| c != '\n')
 4113                                    .filter(|&c| c == target)
 4114                                    .count();
 4115                                current_line_count % 2 == 1
 4116                            } else {
 4117                                false
 4118                            };
 4119
 4120                            if autoclose
 4121                                && bracket_pair.close
 4122                                && following_text_allows_autoclose
 4123                                && preceding_text_allows_autoclose
 4124                                && !is_closing_quote
 4125                            {
 4126                                let anchor = snapshot.anchor_before(selection.end);
 4127                                new_selections.push((selection.map(|_| anchor), text.len()));
 4128                                new_autoclose_regions.push((
 4129                                    anchor,
 4130                                    text.len(),
 4131                                    selection.id,
 4132                                    bracket_pair.clone(),
 4133                                ));
 4134                                edits.push((
 4135                                    selection.range(),
 4136                                    format!("{}{}", text, bracket_pair.end).into(),
 4137                                ));
 4138                                bracket_inserted = true;
 4139                                continue;
 4140                            }
 4141                        }
 4142
 4143                        if let Some(region) = autoclose_region {
 4144                            // If the selection is followed by an auto-inserted closing bracket,
 4145                            // then don't insert that closing bracket again; just move the selection
 4146                            // past the closing bracket.
 4147                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4148                                && text.as_ref() == region.pair.end.as_str()
 4149                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4150                            if should_skip {
 4151                                let anchor = snapshot.anchor_after(selection.end);
 4152                                new_selections
 4153                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4154                                continue;
 4155                            }
 4156                        }
 4157
 4158                        let always_treat_brackets_as_autoclosed = snapshot
 4159                            .language_settings_at(selection.start, cx)
 4160                            .always_treat_brackets_as_autoclosed;
 4161                        if always_treat_brackets_as_autoclosed
 4162                            && is_bracket_pair_end
 4163                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4164                        {
 4165                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4166                            // and the inserted text is a closing bracket and the selection is followed
 4167                            // by the closing bracket then move the selection past the closing bracket.
 4168                            let anchor = snapshot.anchor_after(selection.end);
 4169                            new_selections.push((selection.map(|_| anchor), text.len()));
 4170                            continue;
 4171                        }
 4172                    }
 4173                    // If an opening bracket is 1 character long and is typed while
 4174                    // text is selected, then surround that text with the bracket pair.
 4175                    else if auto_surround
 4176                        && bracket_pair.surround
 4177                        && is_bracket_pair_start
 4178                        && bracket_pair.start.chars().count() == 1
 4179                    {
 4180                        edits.push((selection.start..selection.start, text.clone()));
 4181                        edits.push((
 4182                            selection.end..selection.end,
 4183                            bracket_pair.end.as_str().into(),
 4184                        ));
 4185                        bracket_inserted = true;
 4186                        new_selections.push((
 4187                            Selection {
 4188                                id: selection.id,
 4189                                start: snapshot.anchor_after(selection.start),
 4190                                end: snapshot.anchor_before(selection.end),
 4191                                reversed: selection.reversed,
 4192                                goal: selection.goal,
 4193                            },
 4194                            0,
 4195                        ));
 4196                        continue;
 4197                    }
 4198                }
 4199            }
 4200
 4201            if self.auto_replace_emoji_shortcode
 4202                && selection.is_empty()
 4203                && text.as_ref().ends_with(':')
 4204                && let Some(possible_emoji_short_code) =
 4205                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4206                && !possible_emoji_short_code.is_empty()
 4207                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4208            {
 4209                let emoji_shortcode_start = Point::new(
 4210                    selection.start.row,
 4211                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4212                );
 4213
 4214                // Remove shortcode from buffer
 4215                edits.push((
 4216                    emoji_shortcode_start..selection.start,
 4217                    "".to_string().into(),
 4218                ));
 4219                new_selections.push((
 4220                    Selection {
 4221                        id: selection.id,
 4222                        start: snapshot.anchor_after(emoji_shortcode_start),
 4223                        end: snapshot.anchor_before(selection.start),
 4224                        reversed: selection.reversed,
 4225                        goal: selection.goal,
 4226                    },
 4227                    0,
 4228                ));
 4229
 4230                // Insert emoji
 4231                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4232                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4233                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4234
 4235                continue;
 4236            }
 4237
 4238            // If not handling any auto-close operation, then just replace the selected
 4239            // text with the given input and move the selection to the end of the
 4240            // newly inserted text.
 4241            let anchor = snapshot.anchor_after(selection.end);
 4242            if !self.linked_edit_ranges.is_empty() {
 4243                let start_anchor = snapshot.anchor_before(selection.start);
 4244
 4245                let is_word_char = text.chars().next().is_none_or(|char| {
 4246                    let classifier = snapshot
 4247                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4248                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4249                    classifier.is_word(char)
 4250                });
 4251
 4252                if is_word_char {
 4253                    if let Some(ranges) = self
 4254                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4255                    {
 4256                        for (buffer, edits) in ranges {
 4257                            linked_edits
 4258                                .entry(buffer.clone())
 4259                                .or_default()
 4260                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4261                        }
 4262                    }
 4263                } else {
 4264                    clear_linked_edit_ranges = true;
 4265                }
 4266            }
 4267
 4268            new_selections.push((selection.map(|_| anchor), 0));
 4269            edits.push((selection.start..selection.end, text.clone()));
 4270        }
 4271
 4272        drop(snapshot);
 4273
 4274        self.transact(window, cx, |this, window, cx| {
 4275            if clear_linked_edit_ranges {
 4276                this.linked_edit_ranges.clear();
 4277            }
 4278            let initial_buffer_versions =
 4279                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4280
 4281            this.buffer.update(cx, |buffer, cx| {
 4282                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4283            });
 4284            for (buffer, edits) in linked_edits {
 4285                buffer.update(cx, |buffer, cx| {
 4286                    let snapshot = buffer.snapshot();
 4287                    let edits = edits
 4288                        .into_iter()
 4289                        .map(|(range, text)| {
 4290                            use text::ToPoint as TP;
 4291                            let end_point = TP::to_point(&range.end, &snapshot);
 4292                            let start_point = TP::to_point(&range.start, &snapshot);
 4293                            (start_point..end_point, text)
 4294                        })
 4295                        .sorted_by_key(|(range, _)| range.start);
 4296                    buffer.edit(edits, None, cx);
 4297                })
 4298            }
 4299            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4300            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4301            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4302            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4303                .zip(new_selection_deltas)
 4304                .map(|(selection, delta)| Selection {
 4305                    id: selection.id,
 4306                    start: selection.start + delta,
 4307                    end: selection.end + delta,
 4308                    reversed: selection.reversed,
 4309                    goal: SelectionGoal::None,
 4310                })
 4311                .collect::<Vec<_>>();
 4312
 4313            let mut i = 0;
 4314            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4315                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4316                let start = map.buffer_snapshot.anchor_before(position);
 4317                let end = map.buffer_snapshot.anchor_after(position);
 4318                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4319                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4320                        Ordering::Less => i += 1,
 4321                        Ordering::Greater => break,
 4322                        Ordering::Equal => {
 4323                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4324                                Ordering::Less => i += 1,
 4325                                Ordering::Equal => break,
 4326                                Ordering::Greater => break,
 4327                            }
 4328                        }
 4329                    }
 4330                }
 4331                this.autoclose_regions.insert(
 4332                    i,
 4333                    AutocloseRegion {
 4334                        selection_id,
 4335                        range: start..end,
 4336                        pair,
 4337                    },
 4338                );
 4339            }
 4340
 4341            let had_active_edit_prediction = this.has_active_edit_prediction();
 4342            this.change_selections(
 4343                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4344                window,
 4345                cx,
 4346                |s| s.select(new_selections),
 4347            );
 4348
 4349            if !bracket_inserted
 4350                && let Some(on_type_format_task) =
 4351                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4352            {
 4353                on_type_format_task.detach_and_log_err(cx);
 4354            }
 4355
 4356            let editor_settings = EditorSettings::get_global(cx);
 4357            if bracket_inserted
 4358                && (editor_settings.auto_signature_help
 4359                    || editor_settings.show_signature_help_after_edits)
 4360            {
 4361                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4362            }
 4363
 4364            let trigger_in_words =
 4365                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4366            if this.hard_wrap.is_some() {
 4367                let latest: Range<Point> = this.selections.newest(cx).range();
 4368                if latest.is_empty()
 4369                    && this
 4370                        .buffer()
 4371                        .read(cx)
 4372                        .snapshot(cx)
 4373                        .line_len(MultiBufferRow(latest.start.row))
 4374                        == latest.start.column
 4375                {
 4376                    this.rewrap_impl(
 4377                        RewrapOptions {
 4378                            override_language_settings: true,
 4379                            preserve_existing_whitespace: true,
 4380                        },
 4381                        cx,
 4382                    )
 4383                }
 4384            }
 4385            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4386            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4387            this.refresh_edit_prediction(true, false, window, cx);
 4388            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4389        });
 4390    }
 4391
 4392    fn find_possible_emoji_shortcode_at_position(
 4393        snapshot: &MultiBufferSnapshot,
 4394        position: Point,
 4395    ) -> Option<String> {
 4396        let mut chars = Vec::new();
 4397        let mut found_colon = false;
 4398        for char in snapshot.reversed_chars_at(position).take(100) {
 4399            // Found a possible emoji shortcode in the middle of the buffer
 4400            if found_colon {
 4401                if char.is_whitespace() {
 4402                    chars.reverse();
 4403                    return Some(chars.iter().collect());
 4404                }
 4405                // If the previous character is not a whitespace, we are in the middle of a word
 4406                // and we only want to complete the shortcode if the word is made up of other emojis
 4407                let mut containing_word = String::new();
 4408                for ch in snapshot
 4409                    .reversed_chars_at(position)
 4410                    .skip(chars.len() + 1)
 4411                    .take(100)
 4412                {
 4413                    if ch.is_whitespace() {
 4414                        break;
 4415                    }
 4416                    containing_word.push(ch);
 4417                }
 4418                let containing_word = containing_word.chars().rev().collect::<String>();
 4419                if util::word_consists_of_emojis(containing_word.as_str()) {
 4420                    chars.reverse();
 4421                    return Some(chars.iter().collect());
 4422                }
 4423            }
 4424
 4425            if char.is_whitespace() || !char.is_ascii() {
 4426                return None;
 4427            }
 4428            if char == ':' {
 4429                found_colon = true;
 4430            } else {
 4431                chars.push(char);
 4432            }
 4433        }
 4434        // Found a possible emoji shortcode at the beginning of the buffer
 4435        chars.reverse();
 4436        Some(chars.iter().collect())
 4437    }
 4438
 4439    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4441        self.transact(window, cx, |this, window, cx| {
 4442            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4443                let selections = this.selections.all::<usize>(cx);
 4444                let multi_buffer = this.buffer.read(cx);
 4445                let buffer = multi_buffer.snapshot(cx);
 4446                selections
 4447                    .iter()
 4448                    .map(|selection| {
 4449                        let start_point = selection.start.to_point(&buffer);
 4450                        let mut existing_indent =
 4451                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4452                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4453                        let start = selection.start;
 4454                        let end = selection.end;
 4455                        let selection_is_empty = start == end;
 4456                        let language_scope = buffer.language_scope_at(start);
 4457                        let (
 4458                            comment_delimiter,
 4459                            doc_delimiter,
 4460                            insert_extra_newline,
 4461                            indent_on_newline,
 4462                            indent_on_extra_newline,
 4463                        ) = if let Some(language) = &language_scope {
 4464                            let mut insert_extra_newline =
 4465                                insert_extra_newline_brackets(&buffer, start..end, language)
 4466                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4467
 4468                            // Comment extension on newline is allowed only for cursor selections
 4469                            let comment_delimiter = maybe!({
 4470                                if !selection_is_empty {
 4471                                    return None;
 4472                                }
 4473
 4474                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4475                                    return None;
 4476                                }
 4477
 4478                                let delimiters = language.line_comment_prefixes();
 4479                                let max_len_of_delimiter =
 4480                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4481                                let (snapshot, range) =
 4482                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4483
 4484                                let num_of_whitespaces = snapshot
 4485                                    .chars_for_range(range.clone())
 4486                                    .take_while(|c| c.is_whitespace())
 4487                                    .count();
 4488                                let comment_candidate = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .skip(num_of_whitespaces)
 4491                                    .take(max_len_of_delimiter)
 4492                                    .collect::<String>();
 4493                                let (delimiter, trimmed_len) = delimiters
 4494                                    .iter()
 4495                                    .filter_map(|delimiter| {
 4496                                        let prefix = delimiter.trim_end();
 4497                                        if comment_candidate.starts_with(prefix) {
 4498                                            Some((delimiter, prefix.len()))
 4499                                        } else {
 4500                                            None
 4501                                        }
 4502                                    })
 4503                                    .max_by_key(|(_, len)| *len)?;
 4504
 4505                                if let Some(BlockCommentConfig {
 4506                                    start: block_start, ..
 4507                                }) = language.block_comment()
 4508                                {
 4509                                    let block_start_trimmed = block_start.trim_end();
 4510                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4511                                        let line_content = snapshot
 4512                                            .chars_for_range(range)
 4513                                            .skip(num_of_whitespaces)
 4514                                            .take(block_start_trimmed.len())
 4515                                            .collect::<String>();
 4516
 4517                                        if line_content.starts_with(block_start_trimmed) {
 4518                                            return None;
 4519                                        }
 4520                                    }
 4521                                }
 4522
 4523                                let cursor_is_placed_after_comment_marker =
 4524                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4525                                if cursor_is_placed_after_comment_marker {
 4526                                    Some(delimiter.clone())
 4527                                } else {
 4528                                    None
 4529                                }
 4530                            });
 4531
 4532                            let mut indent_on_newline = IndentSize::spaces(0);
 4533                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4534
 4535                            let doc_delimiter = maybe!({
 4536                                if !selection_is_empty {
 4537                                    return None;
 4538                                }
 4539
 4540                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4541                                    return None;
 4542                                }
 4543
 4544                                let BlockCommentConfig {
 4545                                    start: start_tag,
 4546                                    end: end_tag,
 4547                                    prefix: delimiter,
 4548                                    tab_size: len,
 4549                                } = language.documentation_comment()?;
 4550                                let is_within_block_comment = buffer
 4551                                    .language_scope_at(start_point)
 4552                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4553                                if !is_within_block_comment {
 4554                                    return None;
 4555                                }
 4556
 4557                                let (snapshot, range) =
 4558                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4559
 4560                                let num_of_whitespaces = snapshot
 4561                                    .chars_for_range(range.clone())
 4562                                    .take_while(|c| c.is_whitespace())
 4563                                    .count();
 4564
 4565                                // 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.
 4566                                let column = start_point.column;
 4567                                let cursor_is_after_start_tag = {
 4568                                    let start_tag_len = start_tag.len();
 4569                                    let start_tag_line = snapshot
 4570                                        .chars_for_range(range.clone())
 4571                                        .skip(num_of_whitespaces)
 4572                                        .take(start_tag_len)
 4573                                        .collect::<String>();
 4574                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4575                                        num_of_whitespaces + start_tag_len <= column as usize
 4576                                    } else {
 4577                                        false
 4578                                    }
 4579                                };
 4580
 4581                                let cursor_is_after_delimiter = {
 4582                                    let delimiter_trim = delimiter.trim_end();
 4583                                    let delimiter_line = snapshot
 4584                                        .chars_for_range(range.clone())
 4585                                        .skip(num_of_whitespaces)
 4586                                        .take(delimiter_trim.len())
 4587                                        .collect::<String>();
 4588                                    if delimiter_line.starts_with(delimiter_trim) {
 4589                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4590                                    } else {
 4591                                        false
 4592                                    }
 4593                                };
 4594
 4595                                let cursor_is_before_end_tag_if_exists = {
 4596                                    let mut char_position = 0u32;
 4597                                    let mut end_tag_offset = None;
 4598
 4599                                    'outer: for chunk in snapshot.text_for_range(range) {
 4600                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4601                                            let chars_before_match =
 4602                                                chunk[..byte_pos].chars().count() as u32;
 4603                                            end_tag_offset =
 4604                                                Some(char_position + chars_before_match);
 4605                                            break 'outer;
 4606                                        }
 4607                                        char_position += chunk.chars().count() as u32;
 4608                                    }
 4609
 4610                                    if let Some(end_tag_offset) = end_tag_offset {
 4611                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4612                                        if cursor_is_after_start_tag {
 4613                                            if cursor_is_before_end_tag {
 4614                                                insert_extra_newline = true;
 4615                                            }
 4616                                            let cursor_is_at_start_of_end_tag =
 4617                                                column == end_tag_offset;
 4618                                            if cursor_is_at_start_of_end_tag {
 4619                                                indent_on_extra_newline.len = *len;
 4620                                            }
 4621                                        }
 4622                                        cursor_is_before_end_tag
 4623                                    } else {
 4624                                        true
 4625                                    }
 4626                                };
 4627
 4628                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4629                                    && cursor_is_before_end_tag_if_exists
 4630                                {
 4631                                    if cursor_is_after_start_tag {
 4632                                        indent_on_newline.len = *len;
 4633                                    }
 4634                                    Some(delimiter.clone())
 4635                                } else {
 4636                                    None
 4637                                }
 4638                            });
 4639
 4640                            (
 4641                                comment_delimiter,
 4642                                doc_delimiter,
 4643                                insert_extra_newline,
 4644                                indent_on_newline,
 4645                                indent_on_extra_newline,
 4646                            )
 4647                        } else {
 4648                            (
 4649                                None,
 4650                                None,
 4651                                false,
 4652                                IndentSize::default(),
 4653                                IndentSize::default(),
 4654                            )
 4655                        };
 4656
 4657                        let prevent_auto_indent = doc_delimiter.is_some();
 4658                        let delimiter = comment_delimiter.or(doc_delimiter);
 4659
 4660                        let capacity_for_delimiter =
 4661                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4662                        let mut new_text = String::with_capacity(
 4663                            1 + capacity_for_delimiter
 4664                                + existing_indent.len as usize
 4665                                + indent_on_newline.len as usize
 4666                                + indent_on_extra_newline.len as usize,
 4667                        );
 4668                        new_text.push('\n');
 4669                        new_text.extend(existing_indent.chars());
 4670                        new_text.extend(indent_on_newline.chars());
 4671
 4672                        if let Some(delimiter) = &delimiter {
 4673                            new_text.push_str(delimiter);
 4674                        }
 4675
 4676                        if insert_extra_newline {
 4677                            new_text.push('\n');
 4678                            new_text.extend(existing_indent.chars());
 4679                            new_text.extend(indent_on_extra_newline.chars());
 4680                        }
 4681
 4682                        let anchor = buffer.anchor_after(end);
 4683                        let new_selection = selection.map(|_| anchor);
 4684                        (
 4685                            ((start..end, new_text), prevent_auto_indent),
 4686                            (insert_extra_newline, new_selection),
 4687                        )
 4688                    })
 4689                    .unzip()
 4690            };
 4691
 4692            let mut auto_indent_edits = Vec::new();
 4693            let mut edits = Vec::new();
 4694            for (edit, prevent_auto_indent) in edits_with_flags {
 4695                if prevent_auto_indent {
 4696                    edits.push(edit);
 4697                } else {
 4698                    auto_indent_edits.push(edit);
 4699                }
 4700            }
 4701            if !edits.is_empty() {
 4702                this.edit(edits, cx);
 4703            }
 4704            if !auto_indent_edits.is_empty() {
 4705                this.edit_with_autoindent(auto_indent_edits, cx);
 4706            }
 4707
 4708            let buffer = this.buffer.read(cx).snapshot(cx);
 4709            let new_selections = selection_info
 4710                .into_iter()
 4711                .map(|(extra_newline_inserted, new_selection)| {
 4712                    let mut cursor = new_selection.end.to_point(&buffer);
 4713                    if extra_newline_inserted {
 4714                        cursor.row -= 1;
 4715                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4716                    }
 4717                    new_selection.map(|_| cursor)
 4718                })
 4719                .collect();
 4720
 4721            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4722            this.refresh_edit_prediction(true, false, window, cx);
 4723        });
 4724    }
 4725
 4726    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4728
 4729        let buffer = self.buffer.read(cx);
 4730        let snapshot = buffer.snapshot(cx);
 4731
 4732        let mut edits = Vec::new();
 4733        let mut rows = Vec::new();
 4734
 4735        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4736            let cursor = selection.head();
 4737            let row = cursor.row;
 4738
 4739            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4740
 4741            let newline = "\n".to_string();
 4742            edits.push((start_of_line..start_of_line, newline));
 4743
 4744            rows.push(row + rows_inserted as u32);
 4745        }
 4746
 4747        self.transact(window, cx, |editor, window, cx| {
 4748            editor.edit(edits, cx);
 4749
 4750            editor.change_selections(Default::default(), window, cx, |s| {
 4751                let mut index = 0;
 4752                s.move_cursors_with(|map, _, _| {
 4753                    let row = rows[index];
 4754                    index += 1;
 4755
 4756                    let point = Point::new(row, 0);
 4757                    let boundary = map.next_line_boundary(point).1;
 4758                    let clipped = map.clip_point(boundary, Bias::Left);
 4759
 4760                    (clipped, SelectionGoal::None)
 4761                });
 4762            });
 4763
 4764            let mut indent_edits = Vec::new();
 4765            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4766            for row in rows {
 4767                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4768                for (row, indent) in indents {
 4769                    if indent.len == 0 {
 4770                        continue;
 4771                    }
 4772
 4773                    let text = match indent.kind {
 4774                        IndentKind::Space => " ".repeat(indent.len as usize),
 4775                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4776                    };
 4777                    let point = Point::new(row.0, 0);
 4778                    indent_edits.push((point..point, text));
 4779                }
 4780            }
 4781            editor.edit(indent_edits, cx);
 4782        });
 4783    }
 4784
 4785    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4787
 4788        let buffer = self.buffer.read(cx);
 4789        let snapshot = buffer.snapshot(cx);
 4790
 4791        let mut edits = Vec::new();
 4792        let mut rows = Vec::new();
 4793        let mut rows_inserted = 0;
 4794
 4795        for selection in self.selections.all_adjusted(cx) {
 4796            let cursor = selection.head();
 4797            let row = cursor.row;
 4798
 4799            let point = Point::new(row + 1, 0);
 4800            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4801
 4802            let newline = "\n".to_string();
 4803            edits.push((start_of_line..start_of_line, newline));
 4804
 4805            rows_inserted += 1;
 4806            rows.push(row + rows_inserted);
 4807        }
 4808
 4809        self.transact(window, cx, |editor, window, cx| {
 4810            editor.edit(edits, cx);
 4811
 4812            editor.change_selections(Default::default(), window, cx, |s| {
 4813                let mut index = 0;
 4814                s.move_cursors_with(|map, _, _| {
 4815                    let row = rows[index];
 4816                    index += 1;
 4817
 4818                    let point = Point::new(row, 0);
 4819                    let boundary = map.next_line_boundary(point).1;
 4820                    let clipped = map.clip_point(boundary, Bias::Left);
 4821
 4822                    (clipped, SelectionGoal::None)
 4823                });
 4824            });
 4825
 4826            let mut indent_edits = Vec::new();
 4827            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4828            for row in rows {
 4829                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4830                for (row, indent) in indents {
 4831                    if indent.len == 0 {
 4832                        continue;
 4833                    }
 4834
 4835                    let text = match indent.kind {
 4836                        IndentKind::Space => " ".repeat(indent.len as usize),
 4837                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4838                    };
 4839                    let point = Point::new(row.0, 0);
 4840                    indent_edits.push((point..point, text));
 4841                }
 4842            }
 4843            editor.edit(indent_edits, cx);
 4844        });
 4845    }
 4846
 4847    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4848        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4849            original_indent_columns: Vec::new(),
 4850        });
 4851        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4852    }
 4853
 4854    fn insert_with_autoindent_mode(
 4855        &mut self,
 4856        text: &str,
 4857        autoindent_mode: Option<AutoindentMode>,
 4858        window: &mut Window,
 4859        cx: &mut Context<Self>,
 4860    ) {
 4861        if self.read_only(cx) {
 4862            return;
 4863        }
 4864
 4865        let text: Arc<str> = text.into();
 4866        self.transact(window, cx, |this, window, cx| {
 4867            let old_selections = this.selections.all_adjusted(cx);
 4868            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4869                let anchors = {
 4870                    let snapshot = buffer.read(cx);
 4871                    old_selections
 4872                        .iter()
 4873                        .map(|s| {
 4874                            let anchor = snapshot.anchor_after(s.head());
 4875                            s.map(|_| anchor)
 4876                        })
 4877                        .collect::<Vec<_>>()
 4878                };
 4879                buffer.edit(
 4880                    old_selections
 4881                        .iter()
 4882                        .map(|s| (s.start..s.end, text.clone())),
 4883                    autoindent_mode,
 4884                    cx,
 4885                );
 4886                anchors
 4887            });
 4888
 4889            this.change_selections(Default::default(), window, cx, |s| {
 4890                s.select_anchors(selection_anchors);
 4891            });
 4892
 4893            cx.notify();
 4894        });
 4895    }
 4896
 4897    fn trigger_completion_on_input(
 4898        &mut self,
 4899        text: &str,
 4900        trigger_in_words: bool,
 4901        window: &mut Window,
 4902        cx: &mut Context<Self>,
 4903    ) {
 4904        let completions_source = self
 4905            .context_menu
 4906            .borrow()
 4907            .as_ref()
 4908            .and_then(|menu| match menu {
 4909                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4910                CodeContextMenu::CodeActions(_) => None,
 4911            });
 4912
 4913        match completions_source {
 4914            Some(CompletionsMenuSource::Words { .. }) => {
 4915                self.open_or_update_completions_menu(
 4916                    Some(CompletionsMenuSource::Words {
 4917                        ignore_threshold: false,
 4918                    }),
 4919                    None,
 4920                    window,
 4921                    cx,
 4922                );
 4923            }
 4924            Some(CompletionsMenuSource::Normal)
 4925            | Some(CompletionsMenuSource::SnippetChoices)
 4926            | None
 4927                if self.is_completion_trigger(
 4928                    text,
 4929                    trigger_in_words,
 4930                    completions_source.is_some(),
 4931                    cx,
 4932                ) =>
 4933            {
 4934                self.show_completions(
 4935                    &ShowCompletions {
 4936                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4937                    },
 4938                    window,
 4939                    cx,
 4940                )
 4941            }
 4942            _ => {
 4943                self.hide_context_menu(window, cx);
 4944            }
 4945        }
 4946    }
 4947
 4948    fn is_completion_trigger(
 4949        &self,
 4950        text: &str,
 4951        trigger_in_words: bool,
 4952        menu_is_open: bool,
 4953        cx: &mut Context<Self>,
 4954    ) -> bool {
 4955        let position = self.selections.newest_anchor().head();
 4956        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4957            return false;
 4958        };
 4959
 4960        if let Some(completion_provider) = &self.completion_provider {
 4961            completion_provider.is_completion_trigger(
 4962                &buffer,
 4963                position.text_anchor,
 4964                text,
 4965                trigger_in_words,
 4966                menu_is_open,
 4967                cx,
 4968            )
 4969        } else {
 4970            false
 4971        }
 4972    }
 4973
 4974    /// If any empty selections is touching the start of its innermost containing autoclose
 4975    /// region, expand it to select the brackets.
 4976    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4977        let selections = self.selections.all::<usize>(cx);
 4978        let buffer = self.buffer.read(cx).read(cx);
 4979        let new_selections = self
 4980            .selections_with_autoclose_regions(selections, &buffer)
 4981            .map(|(mut selection, region)| {
 4982                if !selection.is_empty() {
 4983                    return selection;
 4984                }
 4985
 4986                if let Some(region) = region {
 4987                    let mut range = region.range.to_offset(&buffer);
 4988                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4989                        range.start -= region.pair.start.len();
 4990                        if buffer.contains_str_at(range.start, &region.pair.start)
 4991                            && buffer.contains_str_at(range.end, &region.pair.end)
 4992                        {
 4993                            range.end += region.pair.end.len();
 4994                            selection.start = range.start;
 4995                            selection.end = range.end;
 4996
 4997                            return selection;
 4998                        }
 4999                    }
 5000                }
 5001
 5002                let always_treat_brackets_as_autoclosed = buffer
 5003                    .language_settings_at(selection.start, cx)
 5004                    .always_treat_brackets_as_autoclosed;
 5005
 5006                if !always_treat_brackets_as_autoclosed {
 5007                    return selection;
 5008                }
 5009
 5010                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5011                    for (pair, enabled) in scope.brackets() {
 5012                        if !enabled || !pair.close {
 5013                            continue;
 5014                        }
 5015
 5016                        if buffer.contains_str_at(selection.start, &pair.end) {
 5017                            let pair_start_len = pair.start.len();
 5018                            if buffer.contains_str_at(
 5019                                selection.start.saturating_sub(pair_start_len),
 5020                                &pair.start,
 5021                            ) {
 5022                                selection.start -= pair_start_len;
 5023                                selection.end += pair.end.len();
 5024
 5025                                return selection;
 5026                            }
 5027                        }
 5028                    }
 5029                }
 5030
 5031                selection
 5032            })
 5033            .collect();
 5034
 5035        drop(buffer);
 5036        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5037            selections.select(new_selections)
 5038        });
 5039    }
 5040
 5041    /// Iterate the given selections, and for each one, find the smallest surrounding
 5042    /// autoclose region. This uses the ordering of the selections and the autoclose
 5043    /// regions to avoid repeated comparisons.
 5044    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5045        &'a self,
 5046        selections: impl IntoIterator<Item = Selection<D>>,
 5047        buffer: &'a MultiBufferSnapshot,
 5048    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5049        let mut i = 0;
 5050        let mut regions = self.autoclose_regions.as_slice();
 5051        selections.into_iter().map(move |selection| {
 5052            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5053
 5054            let mut enclosing = None;
 5055            while let Some(pair_state) = regions.get(i) {
 5056                if pair_state.range.end.to_offset(buffer) < range.start {
 5057                    regions = &regions[i + 1..];
 5058                    i = 0;
 5059                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5060                    break;
 5061                } else {
 5062                    if pair_state.selection_id == selection.id {
 5063                        enclosing = Some(pair_state);
 5064                    }
 5065                    i += 1;
 5066                }
 5067            }
 5068
 5069            (selection, enclosing)
 5070        })
 5071    }
 5072
 5073    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5074    fn invalidate_autoclose_regions(
 5075        &mut self,
 5076        mut selections: &[Selection<Anchor>],
 5077        buffer: &MultiBufferSnapshot,
 5078    ) {
 5079        self.autoclose_regions.retain(|state| {
 5080            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5081                return false;
 5082            }
 5083
 5084            let mut i = 0;
 5085            while let Some(selection) = selections.get(i) {
 5086                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5087                    selections = &selections[1..];
 5088                    continue;
 5089                }
 5090                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5091                    break;
 5092                }
 5093                if selection.id == state.selection_id {
 5094                    return true;
 5095                } else {
 5096                    i += 1;
 5097                }
 5098            }
 5099            false
 5100        });
 5101    }
 5102
 5103    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5104        let offset = position.to_offset(buffer);
 5105        let (word_range, kind) =
 5106            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5107        if offset > word_range.start && kind == Some(CharKind::Word) {
 5108            Some(
 5109                buffer
 5110                    .text_for_range(word_range.start..offset)
 5111                    .collect::<String>(),
 5112            )
 5113        } else {
 5114            None
 5115        }
 5116    }
 5117
 5118    pub fn toggle_inline_values(
 5119        &mut self,
 5120        _: &ToggleInlineValues,
 5121        _: &mut Window,
 5122        cx: &mut Context<Self>,
 5123    ) {
 5124        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5125
 5126        self.refresh_inline_values(cx);
 5127    }
 5128
 5129    pub fn toggle_inlay_hints(
 5130        &mut self,
 5131        _: &ToggleInlayHints,
 5132        _: &mut Window,
 5133        cx: &mut Context<Self>,
 5134    ) {
 5135        self.refresh_inlay_hints(
 5136            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5137            cx,
 5138        );
 5139    }
 5140
 5141    pub fn inlay_hints_enabled(&self) -> bool {
 5142        self.inlay_hint_cache.enabled
 5143    }
 5144
 5145    pub fn inline_values_enabled(&self) -> bool {
 5146        self.inline_value_cache.enabled
 5147    }
 5148
 5149    #[cfg(any(test, feature = "test-support"))]
 5150    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5151        self.display_map
 5152            .read(cx)
 5153            .current_inlays()
 5154            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5155            .cloned()
 5156            .collect()
 5157    }
 5158
 5159    #[cfg(any(test, feature = "test-support"))]
 5160    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5161        self.display_map
 5162            .read(cx)
 5163            .current_inlays()
 5164            .cloned()
 5165            .collect()
 5166    }
 5167
 5168    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5169        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5170            return;
 5171        }
 5172
 5173        let reason_description = reason.description();
 5174        let ignore_debounce = matches!(
 5175            reason,
 5176            InlayHintRefreshReason::SettingsChange(_)
 5177                | InlayHintRefreshReason::Toggle(_)
 5178                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5179                | InlayHintRefreshReason::ModifiersChanged(_)
 5180        );
 5181        let (invalidate_cache, required_languages) = match reason {
 5182            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5183                match self.inlay_hint_cache.modifiers_override(enabled) {
 5184                    Some(enabled) => {
 5185                        if enabled {
 5186                            (InvalidationStrategy::RefreshRequested, None)
 5187                        } else {
 5188                            self.splice_inlays(
 5189                                &self
 5190                                    .visible_inlay_hints(cx)
 5191                                    .iter()
 5192                                    .map(|inlay| inlay.id)
 5193                                    .collect::<Vec<InlayId>>(),
 5194                                Vec::new(),
 5195                                cx,
 5196                            );
 5197                            return;
 5198                        }
 5199                    }
 5200                    None => return,
 5201                }
 5202            }
 5203            InlayHintRefreshReason::Toggle(enabled) => {
 5204                if self.inlay_hint_cache.toggle(enabled) {
 5205                    if enabled {
 5206                        (InvalidationStrategy::RefreshRequested, None)
 5207                    } else {
 5208                        self.splice_inlays(
 5209                            &self
 5210                                .visible_inlay_hints(cx)
 5211                                .iter()
 5212                                .map(|inlay| inlay.id)
 5213                                .collect::<Vec<InlayId>>(),
 5214                            Vec::new(),
 5215                            cx,
 5216                        );
 5217                        return;
 5218                    }
 5219                } else {
 5220                    return;
 5221                }
 5222            }
 5223            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5224                match self.inlay_hint_cache.update_settings(
 5225                    &self.buffer,
 5226                    new_settings,
 5227                    self.visible_inlay_hints(cx),
 5228                    cx,
 5229                ) {
 5230                    ControlFlow::Break(Some(InlaySplice {
 5231                        to_remove,
 5232                        to_insert,
 5233                    })) => {
 5234                        self.splice_inlays(&to_remove, to_insert, cx);
 5235                        return;
 5236                    }
 5237                    ControlFlow::Break(None) => return,
 5238                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5239                }
 5240            }
 5241            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5242                if let Some(InlaySplice {
 5243                    to_remove,
 5244                    to_insert,
 5245                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5246                {
 5247                    self.splice_inlays(&to_remove, to_insert, cx);
 5248                }
 5249                self.display_map.update(cx, |display_map, _| {
 5250                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5251                });
 5252                return;
 5253            }
 5254            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5255            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5256                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5257            }
 5258            InlayHintRefreshReason::RefreshRequested => {
 5259                (InvalidationStrategy::RefreshRequested, None)
 5260            }
 5261        };
 5262
 5263        if let Some(InlaySplice {
 5264            to_remove,
 5265            to_insert,
 5266        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5267            reason_description,
 5268            self.visible_excerpts(required_languages.as_ref(), cx),
 5269            invalidate_cache,
 5270            ignore_debounce,
 5271            cx,
 5272        ) {
 5273            self.splice_inlays(&to_remove, to_insert, cx);
 5274        }
 5275    }
 5276
 5277    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5278        self.display_map
 5279            .read(cx)
 5280            .current_inlays()
 5281            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5282            .cloned()
 5283            .collect()
 5284    }
 5285
 5286    pub fn visible_excerpts(
 5287        &self,
 5288        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5289        cx: &mut Context<Editor>,
 5290    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5291        let Some(project) = self.project() else {
 5292            return HashMap::default();
 5293        };
 5294        let project = project.read(cx);
 5295        let multi_buffer = self.buffer().read(cx);
 5296        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5297        let multi_buffer_visible_start = self
 5298            .scroll_manager
 5299            .anchor()
 5300            .anchor
 5301            .to_point(&multi_buffer_snapshot);
 5302        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5303            multi_buffer_visible_start
 5304                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5305            Bias::Left,
 5306        );
 5307        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5308        multi_buffer_snapshot
 5309            .range_to_buffer_ranges(multi_buffer_visible_range)
 5310            .into_iter()
 5311            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5312            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5313                let buffer_file = project::File::from_dyn(buffer.file())?;
 5314                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5315                let worktree_entry = buffer_worktree
 5316                    .read(cx)
 5317                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5318                if worktree_entry.is_ignored {
 5319                    return None;
 5320                }
 5321
 5322                let language = buffer.language()?;
 5323                if let Some(restrict_to_languages) = restrict_to_languages
 5324                    && !restrict_to_languages.contains(language)
 5325                {
 5326                    return None;
 5327                }
 5328                Some((
 5329                    excerpt_id,
 5330                    (
 5331                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5332                        buffer.version().clone(),
 5333                        excerpt_visible_range,
 5334                    ),
 5335                ))
 5336            })
 5337            .collect()
 5338    }
 5339
 5340    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5341        TextLayoutDetails {
 5342            text_system: window.text_system().clone(),
 5343            editor_style: self.style.clone().unwrap(),
 5344            rem_size: window.rem_size(),
 5345            scroll_anchor: self.scroll_manager.anchor(),
 5346            visible_rows: self.visible_line_count(),
 5347            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5348        }
 5349    }
 5350
 5351    pub fn splice_inlays(
 5352        &self,
 5353        to_remove: &[InlayId],
 5354        to_insert: Vec<Inlay>,
 5355        cx: &mut Context<Self>,
 5356    ) {
 5357        self.display_map.update(cx, |display_map, cx| {
 5358            display_map.splice_inlays(to_remove, to_insert, cx)
 5359        });
 5360        cx.notify();
 5361    }
 5362
 5363    fn trigger_on_type_formatting(
 5364        &self,
 5365        input: String,
 5366        window: &mut Window,
 5367        cx: &mut Context<Self>,
 5368    ) -> Option<Task<Result<()>>> {
 5369        if input.len() != 1 {
 5370            return None;
 5371        }
 5372
 5373        let project = self.project()?;
 5374        let position = self.selections.newest_anchor().head();
 5375        let (buffer, buffer_position) = self
 5376            .buffer
 5377            .read(cx)
 5378            .text_anchor_for_position(position, cx)?;
 5379
 5380        let settings = language_settings::language_settings(
 5381            buffer
 5382                .read(cx)
 5383                .language_at(buffer_position)
 5384                .map(|l| l.name()),
 5385            buffer.read(cx).file(),
 5386            cx,
 5387        );
 5388        if !settings.use_on_type_format {
 5389            return None;
 5390        }
 5391
 5392        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5393        // hence we do LSP request & edit on host side only — add formats to host's history.
 5394        let push_to_lsp_host_history = true;
 5395        // If this is not the host, append its history with new edits.
 5396        let push_to_client_history = project.read(cx).is_via_collab();
 5397
 5398        let on_type_formatting = project.update(cx, |project, cx| {
 5399            project.on_type_format(
 5400                buffer.clone(),
 5401                buffer_position,
 5402                input,
 5403                push_to_lsp_host_history,
 5404                cx,
 5405            )
 5406        });
 5407        Some(cx.spawn_in(window, async move |editor, cx| {
 5408            if let Some(transaction) = on_type_formatting.await? {
 5409                if push_to_client_history {
 5410                    buffer
 5411                        .update(cx, |buffer, _| {
 5412                            buffer.push_transaction(transaction, Instant::now());
 5413                            buffer.finalize_last_transaction();
 5414                        })
 5415                        .ok();
 5416                }
 5417                editor.update(cx, |editor, cx| {
 5418                    editor.refresh_document_highlights(cx);
 5419                })?;
 5420            }
 5421            Ok(())
 5422        }))
 5423    }
 5424
 5425    pub fn show_word_completions(
 5426        &mut self,
 5427        _: &ShowWordCompletions,
 5428        window: &mut Window,
 5429        cx: &mut Context<Self>,
 5430    ) {
 5431        self.open_or_update_completions_menu(
 5432            Some(CompletionsMenuSource::Words {
 5433                ignore_threshold: true,
 5434            }),
 5435            None,
 5436            window,
 5437            cx,
 5438        );
 5439    }
 5440
 5441    pub fn show_completions(
 5442        &mut self,
 5443        options: &ShowCompletions,
 5444        window: &mut Window,
 5445        cx: &mut Context<Self>,
 5446    ) {
 5447        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5448    }
 5449
 5450    fn open_or_update_completions_menu(
 5451        &mut self,
 5452        requested_source: Option<CompletionsMenuSource>,
 5453        trigger: Option<&str>,
 5454        window: &mut Window,
 5455        cx: &mut Context<Self>,
 5456    ) {
 5457        if self.pending_rename.is_some() {
 5458            return;
 5459        }
 5460
 5461        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5462
 5463        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5464        // inserted and selected. To handle that case, the start of the selection is used so that
 5465        // the menu starts with all choices.
 5466        let position = self
 5467            .selections
 5468            .newest_anchor()
 5469            .start
 5470            .bias_right(&multibuffer_snapshot);
 5471        if position.diff_base_anchor.is_some() {
 5472            return;
 5473        }
 5474        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5475        let Some(buffer) = buffer_position
 5476            .buffer_id
 5477            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5478        else {
 5479            return;
 5480        };
 5481        let buffer_snapshot = buffer.read(cx).snapshot();
 5482
 5483        let query: Option<Arc<String>> =
 5484            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5485                .map(|query| query.into());
 5486
 5487        drop(multibuffer_snapshot);
 5488
 5489        // Hide the current completions menu when query is empty. Without this, cached
 5490        // completions from before the trigger char may be reused (#32774).
 5491        if query.is_none() {
 5492            let menu_is_open = matches!(
 5493                self.context_menu.borrow().as_ref(),
 5494                Some(CodeContextMenu::Completions(_))
 5495            );
 5496            if menu_is_open {
 5497                self.hide_context_menu(window, cx);
 5498            }
 5499        }
 5500
 5501        let mut ignore_word_threshold = false;
 5502        let provider = match requested_source {
 5503            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5504            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5505                ignore_word_threshold = ignore_threshold;
 5506                None
 5507            }
 5508            Some(CompletionsMenuSource::SnippetChoices) => {
 5509                log::error!("bug: SnippetChoices requested_source is not handled");
 5510                None
 5511            }
 5512        };
 5513
 5514        let sort_completions = provider
 5515            .as_ref()
 5516            .is_some_and(|provider| provider.sort_completions());
 5517
 5518        let filter_completions = provider
 5519            .as_ref()
 5520            .is_none_or(|provider| provider.filter_completions());
 5521
 5522        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5523            if filter_completions {
 5524                menu.filter(query.clone(), provider.clone(), window, cx);
 5525            }
 5526            // When `is_incomplete` is false, no need to re-query completions when the current query
 5527            // is a suffix of the initial query.
 5528            if !menu.is_incomplete {
 5529                // If the new query is a suffix of the old query (typing more characters) and
 5530                // the previous result was complete, the existing completions can be filtered.
 5531                //
 5532                // Note that this is always true for snippet completions.
 5533                let query_matches = match (&menu.initial_query, &query) {
 5534                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5535                    (None, _) => true,
 5536                    _ => false,
 5537                };
 5538                if query_matches {
 5539                    let position_matches = if menu.initial_position == position {
 5540                        true
 5541                    } else {
 5542                        let snapshot = self.buffer.read(cx).read(cx);
 5543                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5544                    };
 5545                    if position_matches {
 5546                        return;
 5547                    }
 5548                }
 5549            }
 5550        };
 5551
 5552        let trigger_kind = match trigger {
 5553            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5554                CompletionTriggerKind::TRIGGER_CHARACTER
 5555            }
 5556            _ => CompletionTriggerKind::INVOKED,
 5557        };
 5558        let completion_context = CompletionContext {
 5559            trigger_character: trigger.and_then(|trigger| {
 5560                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5561                    Some(String::from(trigger))
 5562                } else {
 5563                    None
 5564                }
 5565            }),
 5566            trigger_kind,
 5567        };
 5568
 5569        let Anchor {
 5570            excerpt_id: buffer_excerpt_id,
 5571            text_anchor: buffer_position,
 5572            ..
 5573        } = buffer_position;
 5574
 5575        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5576            buffer_snapshot.surrounding_word(buffer_position, None)
 5577        {
 5578            let word_to_exclude = buffer_snapshot
 5579                .text_for_range(word_range.clone())
 5580                .collect::<String>();
 5581            (
 5582                buffer_snapshot.anchor_before(word_range.start)
 5583                    ..buffer_snapshot.anchor_after(buffer_position),
 5584                Some(word_to_exclude),
 5585            )
 5586        } else {
 5587            (buffer_position..buffer_position, None)
 5588        };
 5589
 5590        let language = buffer_snapshot
 5591            .language_at(buffer_position)
 5592            .map(|language| language.name());
 5593
 5594        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5595            .completions
 5596            .clone();
 5597
 5598        let show_completion_documentation = buffer_snapshot
 5599            .settings_at(buffer_position, cx)
 5600            .show_completion_documentation;
 5601
 5602        // The document can be large, so stay in reasonable bounds when searching for words,
 5603        // otherwise completion pop-up might be slow to appear.
 5604        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5605        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5606        let min_word_search = buffer_snapshot.clip_point(
 5607            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5608            Bias::Left,
 5609        );
 5610        let max_word_search = buffer_snapshot.clip_point(
 5611            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5612            Bias::Right,
 5613        );
 5614        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5615            ..buffer_snapshot.point_to_offset(max_word_search);
 5616
 5617        let skip_digits = query
 5618            .as_ref()
 5619            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5620
 5621        let omit_word_completions = !self.word_completions_enabled
 5622            || (!ignore_word_threshold
 5623                && match &query {
 5624                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5625                    None => completion_settings.words_min_length != 0,
 5626                });
 5627
 5628        let (mut words, provider_responses) = match &provider {
 5629            Some(provider) => {
 5630                let provider_responses = provider.completions(
 5631                    buffer_excerpt_id,
 5632                    &buffer,
 5633                    buffer_position,
 5634                    completion_context,
 5635                    window,
 5636                    cx,
 5637                );
 5638
 5639                let words = match (omit_word_completions, completion_settings.words) {
 5640                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5641                        Task::ready(BTreeMap::default())
 5642                    }
 5643                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5644                        .background_spawn(async move {
 5645                            buffer_snapshot.words_in_range(WordsQuery {
 5646                                fuzzy_contents: None,
 5647                                range: word_search_range,
 5648                                skip_digits,
 5649                            })
 5650                        }),
 5651                };
 5652
 5653                (words, provider_responses)
 5654            }
 5655            None => {
 5656                let words = if omit_word_completions {
 5657                    Task::ready(BTreeMap::default())
 5658                } else {
 5659                    cx.background_spawn(async move {
 5660                        buffer_snapshot.words_in_range(WordsQuery {
 5661                            fuzzy_contents: None,
 5662                            range: word_search_range,
 5663                            skip_digits,
 5664                        })
 5665                    })
 5666                };
 5667                (words, Task::ready(Ok(Vec::new())))
 5668            }
 5669        };
 5670
 5671        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5672
 5673        let id = post_inc(&mut self.next_completion_id);
 5674        let task = cx.spawn_in(window, async move |editor, cx| {
 5675            let Ok(()) = editor.update(cx, |this, _| {
 5676                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5677            }) else {
 5678                return;
 5679            };
 5680
 5681            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5682            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5683            let mut completions = Vec::new();
 5684            let mut is_incomplete = false;
 5685            let mut display_options: Option<CompletionDisplayOptions> = None;
 5686            if let Some(provider_responses) = provider_responses.await.log_err()
 5687                && !provider_responses.is_empty()
 5688            {
 5689                for response in provider_responses {
 5690                    completions.extend(response.completions);
 5691                    is_incomplete = is_incomplete || response.is_incomplete;
 5692                    match display_options.as_mut() {
 5693                        None => {
 5694                            display_options = Some(response.display_options);
 5695                        }
 5696                        Some(options) => options.merge(&response.display_options),
 5697                    }
 5698                }
 5699                if completion_settings.words == WordsCompletionMode::Fallback {
 5700                    words = Task::ready(BTreeMap::default());
 5701                }
 5702            }
 5703            let display_options = display_options.unwrap_or_default();
 5704
 5705            let mut words = words.await;
 5706            if let Some(word_to_exclude) = &word_to_exclude {
 5707                words.remove(word_to_exclude);
 5708            }
 5709            for lsp_completion in &completions {
 5710                words.remove(&lsp_completion.new_text);
 5711            }
 5712            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5713                replace_range: word_replace_range.clone(),
 5714                new_text: word.clone(),
 5715                label: CodeLabel::plain(word, None),
 5716                icon_path: None,
 5717                documentation: None,
 5718                source: CompletionSource::BufferWord {
 5719                    word_range,
 5720                    resolved: false,
 5721                },
 5722                insert_text_mode: Some(InsertTextMode::AS_IS),
 5723                confirm: None,
 5724            }));
 5725
 5726            let menu = if completions.is_empty() {
 5727                None
 5728            } else {
 5729                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5730                    let languages = editor
 5731                        .workspace
 5732                        .as_ref()
 5733                        .and_then(|(workspace, _)| workspace.upgrade())
 5734                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5735                    let menu = CompletionsMenu::new(
 5736                        id,
 5737                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5738                        sort_completions,
 5739                        show_completion_documentation,
 5740                        position,
 5741                        query.clone(),
 5742                        is_incomplete,
 5743                        buffer.clone(),
 5744                        completions.into(),
 5745                        display_options,
 5746                        snippet_sort_order,
 5747                        languages,
 5748                        language,
 5749                        cx,
 5750                    );
 5751
 5752                    let query = if filter_completions { query } else { None };
 5753                    let matches_task = if let Some(query) = query {
 5754                        menu.do_async_filtering(query, cx)
 5755                    } else {
 5756                        Task::ready(menu.unfiltered_matches())
 5757                    };
 5758                    (menu, matches_task)
 5759                }) else {
 5760                    return;
 5761                };
 5762
 5763                let matches = matches_task.await;
 5764
 5765                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5766                    // Newer menu already set, so exit.
 5767                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5768                        editor.context_menu.borrow().as_ref()
 5769                        && prev_menu.id > id
 5770                    {
 5771                        return;
 5772                    };
 5773
 5774                    // Only valid to take prev_menu because it the new menu is immediately set
 5775                    // below, or the menu is hidden.
 5776                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5777                        editor.context_menu.borrow_mut().take()
 5778                    {
 5779                        let position_matches =
 5780                            if prev_menu.initial_position == menu.initial_position {
 5781                                true
 5782                            } else {
 5783                                let snapshot = editor.buffer.read(cx).read(cx);
 5784                                prev_menu.initial_position.to_offset(&snapshot)
 5785                                    == menu.initial_position.to_offset(&snapshot)
 5786                            };
 5787                        if position_matches {
 5788                            // Preserve markdown cache before `set_filter_results` because it will
 5789                            // try to populate the documentation cache.
 5790                            menu.preserve_markdown_cache(prev_menu);
 5791                        }
 5792                    };
 5793
 5794                    menu.set_filter_results(matches, provider, window, cx);
 5795                }) else {
 5796                    return;
 5797                };
 5798
 5799                menu.visible().then_some(menu)
 5800            };
 5801
 5802            editor
 5803                .update_in(cx, |editor, window, cx| {
 5804                    if editor.focus_handle.is_focused(window)
 5805                        && let Some(menu) = menu
 5806                    {
 5807                        *editor.context_menu.borrow_mut() =
 5808                            Some(CodeContextMenu::Completions(menu));
 5809
 5810                        crate::hover_popover::hide_hover(editor, cx);
 5811                        if editor.show_edit_predictions_in_menu() {
 5812                            editor.update_visible_edit_prediction(window, cx);
 5813                        } else {
 5814                            editor.discard_edit_prediction(false, cx);
 5815                        }
 5816
 5817                        cx.notify();
 5818                        return;
 5819                    }
 5820
 5821                    if editor.completion_tasks.len() <= 1 {
 5822                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5823                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5824                        // If it was already hidden and we don't show edit predictions in the menu,
 5825                        // we should also show the edit prediction when available.
 5826                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5827                            editor.update_visible_edit_prediction(window, cx);
 5828                        }
 5829                    }
 5830                })
 5831                .ok();
 5832        });
 5833
 5834        self.completion_tasks.push((id, task));
 5835    }
 5836
 5837    #[cfg(feature = "test-support")]
 5838    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5839        let menu = self.context_menu.borrow();
 5840        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5841            let completions = menu.completions.borrow();
 5842            Some(completions.to_vec())
 5843        } else {
 5844            None
 5845        }
 5846    }
 5847
 5848    pub fn with_completions_menu_matching_id<R>(
 5849        &self,
 5850        id: CompletionId,
 5851        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5852    ) -> R {
 5853        let mut context_menu = self.context_menu.borrow_mut();
 5854        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5855            return f(None);
 5856        };
 5857        if completions_menu.id != id {
 5858            return f(None);
 5859        }
 5860        f(Some(completions_menu))
 5861    }
 5862
 5863    pub fn confirm_completion(
 5864        &mut self,
 5865        action: &ConfirmCompletion,
 5866        window: &mut Window,
 5867        cx: &mut Context<Self>,
 5868    ) -> Option<Task<Result<()>>> {
 5869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5870        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5871    }
 5872
 5873    pub fn confirm_completion_insert(
 5874        &mut self,
 5875        _: &ConfirmCompletionInsert,
 5876        window: &mut Window,
 5877        cx: &mut Context<Self>,
 5878    ) -> Option<Task<Result<()>>> {
 5879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5880        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5881    }
 5882
 5883    pub fn confirm_completion_replace(
 5884        &mut self,
 5885        _: &ConfirmCompletionReplace,
 5886        window: &mut Window,
 5887        cx: &mut Context<Self>,
 5888    ) -> Option<Task<Result<()>>> {
 5889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5890        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5891    }
 5892
 5893    pub fn compose_completion(
 5894        &mut self,
 5895        action: &ComposeCompletion,
 5896        window: &mut Window,
 5897        cx: &mut Context<Self>,
 5898    ) -> Option<Task<Result<()>>> {
 5899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5900        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5901    }
 5902
 5903    fn do_completion(
 5904        &mut self,
 5905        item_ix: Option<usize>,
 5906        intent: CompletionIntent,
 5907        window: &mut Window,
 5908        cx: &mut Context<Editor>,
 5909    ) -> Option<Task<Result<()>>> {
 5910        use language::ToOffset as _;
 5911
 5912        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5913        else {
 5914            return None;
 5915        };
 5916
 5917        let candidate_id = {
 5918            let entries = completions_menu.entries.borrow();
 5919            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5920            if self.show_edit_predictions_in_menu() {
 5921                self.discard_edit_prediction(true, cx);
 5922            }
 5923            mat.candidate_id
 5924        };
 5925
 5926        let completion = completions_menu
 5927            .completions
 5928            .borrow()
 5929            .get(candidate_id)?
 5930            .clone();
 5931        cx.stop_propagation();
 5932
 5933        let buffer_handle = completions_menu.buffer.clone();
 5934
 5935        let CompletionEdit {
 5936            new_text,
 5937            snippet,
 5938            replace_range,
 5939        } = process_completion_for_edit(
 5940            &completion,
 5941            intent,
 5942            &buffer_handle,
 5943            &completions_menu.initial_position.text_anchor,
 5944            cx,
 5945        );
 5946
 5947        let buffer = buffer_handle.read(cx);
 5948        let snapshot = self.buffer.read(cx).snapshot(cx);
 5949        let newest_anchor = self.selections.newest_anchor();
 5950        let replace_range_multibuffer = {
 5951            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5952            let multibuffer_anchor = snapshot
 5953                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5954                .unwrap()
 5955                ..snapshot
 5956                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5957                    .unwrap();
 5958            multibuffer_anchor.start.to_offset(&snapshot)
 5959                ..multibuffer_anchor.end.to_offset(&snapshot)
 5960        };
 5961        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5962            return None;
 5963        }
 5964
 5965        let old_text = buffer
 5966            .text_for_range(replace_range.clone())
 5967            .collect::<String>();
 5968        let lookbehind = newest_anchor
 5969            .start
 5970            .text_anchor
 5971            .to_offset(buffer)
 5972            .saturating_sub(replace_range.start);
 5973        let lookahead = replace_range
 5974            .end
 5975            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5976        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5977        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5978
 5979        let selections = self.selections.all::<usize>(cx);
 5980        let mut ranges = Vec::new();
 5981        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5982
 5983        for selection in &selections {
 5984            let range = if selection.id == newest_anchor.id {
 5985                replace_range_multibuffer.clone()
 5986            } else {
 5987                let mut range = selection.range();
 5988
 5989                // if prefix is present, don't duplicate it
 5990                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5991                    range.start = range.start.saturating_sub(lookbehind);
 5992
 5993                    // if suffix is also present, mimic the newest cursor and replace it
 5994                    if selection.id != newest_anchor.id
 5995                        && snapshot.contains_str_at(range.end, suffix)
 5996                    {
 5997                        range.end += lookahead;
 5998                    }
 5999                }
 6000                range
 6001            };
 6002
 6003            ranges.push(range.clone());
 6004
 6005            if !self.linked_edit_ranges.is_empty() {
 6006                let start_anchor = snapshot.anchor_before(range.start);
 6007                let end_anchor = snapshot.anchor_after(range.end);
 6008                if let Some(ranges) = self
 6009                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6010                {
 6011                    for (buffer, edits) in ranges {
 6012                        linked_edits
 6013                            .entry(buffer.clone())
 6014                            .or_default()
 6015                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6016                    }
 6017                }
 6018            }
 6019        }
 6020
 6021        let common_prefix_len = old_text
 6022            .chars()
 6023            .zip(new_text.chars())
 6024            .take_while(|(a, b)| a == b)
 6025            .map(|(a, _)| a.len_utf8())
 6026            .sum::<usize>();
 6027
 6028        cx.emit(EditorEvent::InputHandled {
 6029            utf16_range_to_replace: None,
 6030            text: new_text[common_prefix_len..].into(),
 6031        });
 6032
 6033        self.transact(window, cx, |editor, window, cx| {
 6034            if let Some(mut snippet) = snippet {
 6035                snippet.text = new_text.to_string();
 6036                editor
 6037                    .insert_snippet(&ranges, snippet, window, cx)
 6038                    .log_err();
 6039            } else {
 6040                editor.buffer.update(cx, |multi_buffer, cx| {
 6041                    let auto_indent = match completion.insert_text_mode {
 6042                        Some(InsertTextMode::AS_IS) => None,
 6043                        _ => editor.autoindent_mode.clone(),
 6044                    };
 6045                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6046                    multi_buffer.edit(edits, auto_indent, cx);
 6047                });
 6048            }
 6049            for (buffer, edits) in linked_edits {
 6050                buffer.update(cx, |buffer, cx| {
 6051                    let snapshot = buffer.snapshot();
 6052                    let edits = edits
 6053                        .into_iter()
 6054                        .map(|(range, text)| {
 6055                            use text::ToPoint as TP;
 6056                            let end_point = TP::to_point(&range.end, &snapshot);
 6057                            let start_point = TP::to_point(&range.start, &snapshot);
 6058                            (start_point..end_point, text)
 6059                        })
 6060                        .sorted_by_key(|(range, _)| range.start);
 6061                    buffer.edit(edits, None, cx);
 6062                })
 6063            }
 6064
 6065            editor.refresh_edit_prediction(true, false, window, cx);
 6066        });
 6067        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6068
 6069        let show_new_completions_on_confirm = completion
 6070            .confirm
 6071            .as_ref()
 6072            .is_some_and(|confirm| confirm(intent, window, cx));
 6073        if show_new_completions_on_confirm {
 6074            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6075        }
 6076
 6077        let provider = self.completion_provider.as_ref()?;
 6078        drop(completion);
 6079        let apply_edits = provider.apply_additional_edits_for_completion(
 6080            buffer_handle,
 6081            completions_menu.completions.clone(),
 6082            candidate_id,
 6083            true,
 6084            cx,
 6085        );
 6086
 6087        let editor_settings = EditorSettings::get_global(cx);
 6088        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6089            // After the code completion is finished, users often want to know what signatures are needed.
 6090            // so we should automatically call signature_help
 6091            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6092        }
 6093
 6094        Some(cx.foreground_executor().spawn(async move {
 6095            apply_edits.await?;
 6096            Ok(())
 6097        }))
 6098    }
 6099
 6100    pub fn toggle_code_actions(
 6101        &mut self,
 6102        action: &ToggleCodeActions,
 6103        window: &mut Window,
 6104        cx: &mut Context<Self>,
 6105    ) {
 6106        let quick_launch = action.quick_launch;
 6107        let mut context_menu = self.context_menu.borrow_mut();
 6108        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6109            if code_actions.deployed_from == action.deployed_from {
 6110                // Toggle if we're selecting the same one
 6111                *context_menu = None;
 6112                cx.notify();
 6113                return;
 6114            } else {
 6115                // Otherwise, clear it and start a new one
 6116                *context_menu = None;
 6117                cx.notify();
 6118            }
 6119        }
 6120        drop(context_menu);
 6121        let snapshot = self.snapshot(window, cx);
 6122        let deployed_from = action.deployed_from.clone();
 6123        let action = action.clone();
 6124        self.completion_tasks.clear();
 6125        self.discard_edit_prediction(false, cx);
 6126
 6127        let multibuffer_point = match &action.deployed_from {
 6128            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6129                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6130            }
 6131            _ => self.selections.newest::<Point>(cx).head(),
 6132        };
 6133        let Some((buffer, buffer_row)) = snapshot
 6134            .buffer_snapshot
 6135            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6136            .and_then(|(buffer_snapshot, range)| {
 6137                self.buffer()
 6138                    .read(cx)
 6139                    .buffer(buffer_snapshot.remote_id())
 6140                    .map(|buffer| (buffer, range.start.row))
 6141            })
 6142        else {
 6143            return;
 6144        };
 6145        let buffer_id = buffer.read(cx).remote_id();
 6146        let tasks = self
 6147            .tasks
 6148            .get(&(buffer_id, buffer_row))
 6149            .map(|t| Arc::new(t.to_owned()));
 6150
 6151        if !self.focus_handle.is_focused(window) {
 6152            return;
 6153        }
 6154        let project = self.project.clone();
 6155
 6156        let code_actions_task = match deployed_from {
 6157            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6158            _ => self.code_actions(buffer_row, window, cx),
 6159        };
 6160
 6161        let runnable_task = match deployed_from {
 6162            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6163            _ => {
 6164                let mut task_context_task = Task::ready(None);
 6165                if let Some(tasks) = &tasks
 6166                    && let Some(project) = project
 6167                {
 6168                    task_context_task =
 6169                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6170                }
 6171
 6172                cx.spawn_in(window, {
 6173                    let buffer = buffer.clone();
 6174                    async move |editor, cx| {
 6175                        let task_context = task_context_task.await;
 6176
 6177                        let resolved_tasks =
 6178                            tasks
 6179                                .zip(task_context.clone())
 6180                                .map(|(tasks, task_context)| ResolvedTasks {
 6181                                    templates: tasks.resolve(&task_context).collect(),
 6182                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6183                                        multibuffer_point.row,
 6184                                        tasks.column,
 6185                                    )),
 6186                                });
 6187                        let debug_scenarios = editor
 6188                            .update(cx, |editor, cx| {
 6189                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6190                            })?
 6191                            .await;
 6192                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6193                    }
 6194                })
 6195            }
 6196        };
 6197
 6198        cx.spawn_in(window, async move |editor, cx| {
 6199            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6200            let code_actions = code_actions_task.await;
 6201            let spawn_straight_away = quick_launch
 6202                && resolved_tasks
 6203                    .as_ref()
 6204                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6205                && code_actions
 6206                    .as_ref()
 6207                    .is_none_or(|actions| actions.is_empty())
 6208                && debug_scenarios.is_empty();
 6209
 6210            editor.update_in(cx, |editor, window, cx| {
 6211                crate::hover_popover::hide_hover(editor, cx);
 6212                let actions = CodeActionContents::new(
 6213                    resolved_tasks,
 6214                    code_actions,
 6215                    debug_scenarios,
 6216                    task_context.unwrap_or_default(),
 6217                );
 6218
 6219                // Don't show the menu if there are no actions available
 6220                if actions.is_empty() {
 6221                    cx.notify();
 6222                    return Task::ready(Ok(()));
 6223                }
 6224
 6225                *editor.context_menu.borrow_mut() =
 6226                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6227                        buffer,
 6228                        actions,
 6229                        selected_item: Default::default(),
 6230                        scroll_handle: UniformListScrollHandle::default(),
 6231                        deployed_from,
 6232                    }));
 6233                cx.notify();
 6234                if spawn_straight_away
 6235                    && let Some(task) = editor.confirm_code_action(
 6236                        &ConfirmCodeAction { item_ix: Some(0) },
 6237                        window,
 6238                        cx,
 6239                    )
 6240                {
 6241                    return task;
 6242                }
 6243
 6244                Task::ready(Ok(()))
 6245            })
 6246        })
 6247        .detach_and_log_err(cx);
 6248    }
 6249
 6250    fn debug_scenarios(
 6251        &mut self,
 6252        resolved_tasks: &Option<ResolvedTasks>,
 6253        buffer: &Entity<Buffer>,
 6254        cx: &mut App,
 6255    ) -> Task<Vec<task::DebugScenario>> {
 6256        maybe!({
 6257            let project = self.project()?;
 6258            let dap_store = project.read(cx).dap_store();
 6259            let mut scenarios = vec![];
 6260            let resolved_tasks = resolved_tasks.as_ref()?;
 6261            let buffer = buffer.read(cx);
 6262            let language = buffer.language()?;
 6263            let file = buffer.file();
 6264            let debug_adapter = language_settings(language.name().into(), file, cx)
 6265                .debuggers
 6266                .first()
 6267                .map(SharedString::from)
 6268                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6269
 6270            dap_store.update(cx, |dap_store, cx| {
 6271                for (_, task) in &resolved_tasks.templates {
 6272                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6273                        task.original_task().clone(),
 6274                        debug_adapter.clone().into(),
 6275                        task.display_label().to_owned().into(),
 6276                        cx,
 6277                    );
 6278                    scenarios.push(maybe_scenario);
 6279                }
 6280            });
 6281            Some(cx.background_spawn(async move {
 6282                futures::future::join_all(scenarios)
 6283                    .await
 6284                    .into_iter()
 6285                    .flatten()
 6286                    .collect::<Vec<_>>()
 6287            }))
 6288        })
 6289        .unwrap_or_else(|| Task::ready(vec![]))
 6290    }
 6291
 6292    fn code_actions(
 6293        &mut self,
 6294        buffer_row: u32,
 6295        window: &mut Window,
 6296        cx: &mut Context<Self>,
 6297    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6298        let mut task = self.code_actions_task.take();
 6299        cx.spawn_in(window, async move |editor, cx| {
 6300            while let Some(prev_task) = task {
 6301                prev_task.await.log_err();
 6302                task = editor
 6303                    .update(cx, |this, _| this.code_actions_task.take())
 6304                    .ok()?;
 6305            }
 6306
 6307            editor
 6308                .update(cx, |editor, cx| {
 6309                    editor
 6310                        .available_code_actions
 6311                        .clone()
 6312                        .and_then(|(location, code_actions)| {
 6313                            let snapshot = location.buffer.read(cx).snapshot();
 6314                            let point_range = location.range.to_point(&snapshot);
 6315                            let point_range = point_range.start.row..=point_range.end.row;
 6316                            if point_range.contains(&buffer_row) {
 6317                                Some(code_actions)
 6318                            } else {
 6319                                None
 6320                            }
 6321                        })
 6322                })
 6323                .ok()
 6324                .flatten()
 6325        })
 6326    }
 6327
 6328    pub fn confirm_code_action(
 6329        &mut self,
 6330        action: &ConfirmCodeAction,
 6331        window: &mut Window,
 6332        cx: &mut Context<Self>,
 6333    ) -> Option<Task<Result<()>>> {
 6334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6335
 6336        let actions_menu =
 6337            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6338                menu
 6339            } else {
 6340                return None;
 6341            };
 6342
 6343        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6344        let action = actions_menu.actions.get(action_ix)?;
 6345        let title = action.label();
 6346        let buffer = actions_menu.buffer;
 6347        let workspace = self.workspace()?;
 6348
 6349        match action {
 6350            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6351                workspace.update(cx, |workspace, cx| {
 6352                    workspace.schedule_resolved_task(
 6353                        task_source_kind,
 6354                        resolved_task,
 6355                        false,
 6356                        window,
 6357                        cx,
 6358                    );
 6359
 6360                    Some(Task::ready(Ok(())))
 6361                })
 6362            }
 6363            CodeActionsItem::CodeAction {
 6364                excerpt_id,
 6365                action,
 6366                provider,
 6367            } => {
 6368                let apply_code_action =
 6369                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6370                let workspace = workspace.downgrade();
 6371                Some(cx.spawn_in(window, async move |editor, cx| {
 6372                    let project_transaction = apply_code_action.await?;
 6373                    Self::open_project_transaction(
 6374                        &editor,
 6375                        workspace,
 6376                        project_transaction,
 6377                        title,
 6378                        cx,
 6379                    )
 6380                    .await
 6381                }))
 6382            }
 6383            CodeActionsItem::DebugScenario(scenario) => {
 6384                let context = actions_menu.actions.context;
 6385
 6386                workspace.update(cx, |workspace, cx| {
 6387                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6388                    workspace.start_debug_session(
 6389                        scenario,
 6390                        context,
 6391                        Some(buffer),
 6392                        None,
 6393                        window,
 6394                        cx,
 6395                    );
 6396                });
 6397                Some(Task::ready(Ok(())))
 6398            }
 6399        }
 6400    }
 6401
 6402    pub async fn open_project_transaction(
 6403        editor: &WeakEntity<Editor>,
 6404        workspace: WeakEntity<Workspace>,
 6405        transaction: ProjectTransaction,
 6406        title: String,
 6407        cx: &mut AsyncWindowContext,
 6408    ) -> Result<()> {
 6409        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6410        cx.update(|_, cx| {
 6411            entries.sort_unstable_by_key(|(buffer, _)| {
 6412                buffer.read(cx).file().map(|f| f.path().clone())
 6413            });
 6414        })?;
 6415
 6416        // If the project transaction's edits are all contained within this editor, then
 6417        // avoid opening a new editor to display them.
 6418
 6419        if let Some((buffer, transaction)) = entries.first() {
 6420            if entries.len() == 1 {
 6421                let excerpt = editor.update(cx, |editor, cx| {
 6422                    editor
 6423                        .buffer()
 6424                        .read(cx)
 6425                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6426                })?;
 6427                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6428                    && excerpted_buffer == *buffer
 6429                {
 6430                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6431                        let excerpt_range = excerpt_range.to_offset(buffer);
 6432                        buffer
 6433                            .edited_ranges_for_transaction::<usize>(transaction)
 6434                            .all(|range| {
 6435                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6436                            })
 6437                    })?;
 6438
 6439                    if all_edits_within_excerpt {
 6440                        return Ok(());
 6441                    }
 6442                }
 6443            }
 6444        } else {
 6445            return Ok(());
 6446        }
 6447
 6448        let mut ranges_to_highlight = Vec::new();
 6449        let excerpt_buffer = cx.new(|cx| {
 6450            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6451            for (buffer_handle, transaction) in &entries {
 6452                let edited_ranges = buffer_handle
 6453                    .read(cx)
 6454                    .edited_ranges_for_transaction::<Point>(transaction)
 6455                    .collect::<Vec<_>>();
 6456                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6457                    PathKey::for_buffer(buffer_handle, cx),
 6458                    buffer_handle.clone(),
 6459                    edited_ranges,
 6460                    multibuffer_context_lines(cx),
 6461                    cx,
 6462                );
 6463
 6464                ranges_to_highlight.extend(ranges);
 6465            }
 6466            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6467            multibuffer
 6468        })?;
 6469
 6470        workspace.update_in(cx, |workspace, window, cx| {
 6471            let project = workspace.project().clone();
 6472            let editor =
 6473                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6474            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6475            editor.update(cx, |editor, cx| {
 6476                editor.highlight_background::<Self>(
 6477                    &ranges_to_highlight,
 6478                    |theme| theme.colors().editor_highlighted_line_background,
 6479                    cx,
 6480                );
 6481            });
 6482        })?;
 6483
 6484        Ok(())
 6485    }
 6486
 6487    pub fn clear_code_action_providers(&mut self) {
 6488        self.code_action_providers.clear();
 6489        self.available_code_actions.take();
 6490    }
 6491
 6492    pub fn add_code_action_provider(
 6493        &mut self,
 6494        provider: Rc<dyn CodeActionProvider>,
 6495        window: &mut Window,
 6496        cx: &mut Context<Self>,
 6497    ) {
 6498        if self
 6499            .code_action_providers
 6500            .iter()
 6501            .any(|existing_provider| existing_provider.id() == provider.id())
 6502        {
 6503            return;
 6504        }
 6505
 6506        self.code_action_providers.push(provider);
 6507        self.refresh_code_actions(window, cx);
 6508    }
 6509
 6510    pub fn remove_code_action_provider(
 6511        &mut self,
 6512        id: Arc<str>,
 6513        window: &mut Window,
 6514        cx: &mut Context<Self>,
 6515    ) {
 6516        self.code_action_providers
 6517            .retain(|provider| provider.id() != id);
 6518        self.refresh_code_actions(window, cx);
 6519    }
 6520
 6521    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6522        !self.code_action_providers.is_empty()
 6523            && EditorSettings::get_global(cx).toolbar.code_actions
 6524    }
 6525
 6526    pub fn has_available_code_actions(&self) -> bool {
 6527        self.available_code_actions
 6528            .as_ref()
 6529            .is_some_and(|(_, actions)| !actions.is_empty())
 6530    }
 6531
 6532    fn render_inline_code_actions(
 6533        &self,
 6534        icon_size: ui::IconSize,
 6535        display_row: DisplayRow,
 6536        is_active: bool,
 6537        cx: &mut Context<Self>,
 6538    ) -> AnyElement {
 6539        let show_tooltip = !self.context_menu_visible();
 6540        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6541            .icon_size(icon_size)
 6542            .shape(ui::IconButtonShape::Square)
 6543            .icon_color(ui::Color::Hidden)
 6544            .toggle_state(is_active)
 6545            .when(show_tooltip, |this| {
 6546                this.tooltip({
 6547                    let focus_handle = self.focus_handle.clone();
 6548                    move |window, cx| {
 6549                        Tooltip::for_action_in(
 6550                            "Toggle Code Actions",
 6551                            &ToggleCodeActions {
 6552                                deployed_from: None,
 6553                                quick_launch: false,
 6554                            },
 6555                            &focus_handle,
 6556                            window,
 6557                            cx,
 6558                        )
 6559                    }
 6560                })
 6561            })
 6562            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6563                window.focus(&editor.focus_handle(cx));
 6564                editor.toggle_code_actions(
 6565                    &crate::actions::ToggleCodeActions {
 6566                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6567                            display_row,
 6568                        )),
 6569                        quick_launch: false,
 6570                    },
 6571                    window,
 6572                    cx,
 6573                );
 6574            }))
 6575            .into_any_element()
 6576    }
 6577
 6578    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6579        &self.context_menu
 6580    }
 6581
 6582    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6583        let newest_selection = self.selections.newest_anchor().clone();
 6584        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6585        let buffer = self.buffer.read(cx);
 6586        if newest_selection.head().diff_base_anchor.is_some() {
 6587            return None;
 6588        }
 6589        let (start_buffer, start) =
 6590            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6591        let (end_buffer, end) =
 6592            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6593        if start_buffer != end_buffer {
 6594            return None;
 6595        }
 6596
 6597        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6598            cx.background_executor()
 6599                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6600                .await;
 6601
 6602            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6603                let providers = this.code_action_providers.clone();
 6604                let tasks = this
 6605                    .code_action_providers
 6606                    .iter()
 6607                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6608                    .collect::<Vec<_>>();
 6609                (providers, tasks)
 6610            })?;
 6611
 6612            let mut actions = Vec::new();
 6613            for (provider, provider_actions) in
 6614                providers.into_iter().zip(future::join_all(tasks).await)
 6615            {
 6616                if let Some(provider_actions) = provider_actions.log_err() {
 6617                    actions.extend(provider_actions.into_iter().map(|action| {
 6618                        AvailableCodeAction {
 6619                            excerpt_id: newest_selection.start.excerpt_id,
 6620                            action,
 6621                            provider: provider.clone(),
 6622                        }
 6623                    }));
 6624                }
 6625            }
 6626
 6627            this.update(cx, |this, cx| {
 6628                this.available_code_actions = if actions.is_empty() {
 6629                    None
 6630                } else {
 6631                    Some((
 6632                        Location {
 6633                            buffer: start_buffer,
 6634                            range: start..end,
 6635                        },
 6636                        actions.into(),
 6637                    ))
 6638                };
 6639                cx.notify();
 6640            })
 6641        }));
 6642        None
 6643    }
 6644
 6645    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6646        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6647            self.show_git_blame_inline = false;
 6648
 6649            self.show_git_blame_inline_delay_task =
 6650                Some(cx.spawn_in(window, async move |this, cx| {
 6651                    cx.background_executor().timer(delay).await;
 6652
 6653                    this.update(cx, |this, cx| {
 6654                        this.show_git_blame_inline = true;
 6655                        cx.notify();
 6656                    })
 6657                    .log_err();
 6658                }));
 6659        }
 6660    }
 6661
 6662    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6663        let snapshot = self.snapshot(window, cx);
 6664        let cursor = self.selections.newest::<Point>(cx).head();
 6665        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6666        else {
 6667            return;
 6668        };
 6669
 6670        let Some(blame) = self.blame.as_ref() else {
 6671            return;
 6672        };
 6673
 6674        let row_info = RowInfo {
 6675            buffer_id: Some(buffer.remote_id()),
 6676            buffer_row: Some(point.row),
 6677            ..Default::default()
 6678        };
 6679        let Some((buffer, blame_entry)) = blame
 6680            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6681            .flatten()
 6682        else {
 6683            return;
 6684        };
 6685
 6686        let anchor = self.selections.newest_anchor().head();
 6687        let position = self.to_pixel_point(anchor, &snapshot, window);
 6688        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6689            self.show_blame_popover(
 6690                buffer,
 6691                &blame_entry,
 6692                position + last_bounds.origin,
 6693                true,
 6694                cx,
 6695            );
 6696        };
 6697    }
 6698
 6699    fn show_blame_popover(
 6700        &mut self,
 6701        buffer: BufferId,
 6702        blame_entry: &BlameEntry,
 6703        position: gpui::Point<Pixels>,
 6704        ignore_timeout: bool,
 6705        cx: &mut Context<Self>,
 6706    ) {
 6707        if let Some(state) = &mut self.inline_blame_popover {
 6708            state.hide_task.take();
 6709        } else {
 6710            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6711            let blame_entry = blame_entry.clone();
 6712            let show_task = cx.spawn(async move |editor, cx| {
 6713                if !ignore_timeout {
 6714                    cx.background_executor()
 6715                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6716                        .await;
 6717                }
 6718                editor
 6719                    .update(cx, |editor, cx| {
 6720                        editor.inline_blame_popover_show_task.take();
 6721                        let Some(blame) = editor.blame.as_ref() else {
 6722                            return;
 6723                        };
 6724                        let blame = blame.read(cx);
 6725                        let details = blame.details_for_entry(buffer, &blame_entry);
 6726                        let markdown = cx.new(|cx| {
 6727                            Markdown::new(
 6728                                details
 6729                                    .as_ref()
 6730                                    .map(|message| message.message.clone())
 6731                                    .unwrap_or_default(),
 6732                                None,
 6733                                None,
 6734                                cx,
 6735                            )
 6736                        });
 6737                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6738                            position,
 6739                            hide_task: None,
 6740                            popover_bounds: None,
 6741                            popover_state: InlineBlamePopoverState {
 6742                                scroll_handle: ScrollHandle::new(),
 6743                                commit_message: details,
 6744                                markdown,
 6745                            },
 6746                            keyboard_grace: ignore_timeout,
 6747                        });
 6748                        cx.notify();
 6749                    })
 6750                    .ok();
 6751            });
 6752            self.inline_blame_popover_show_task = Some(show_task);
 6753        }
 6754    }
 6755
 6756    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6757        self.inline_blame_popover_show_task.take();
 6758        if let Some(state) = &mut self.inline_blame_popover {
 6759            let hide_task = cx.spawn(async move |editor, cx| {
 6760                cx.background_executor()
 6761                    .timer(std::time::Duration::from_millis(100))
 6762                    .await;
 6763                editor
 6764                    .update(cx, |editor, cx| {
 6765                        editor.inline_blame_popover.take();
 6766                        cx.notify();
 6767                    })
 6768                    .ok();
 6769            });
 6770            state.hide_task = Some(hide_task);
 6771        }
 6772    }
 6773
 6774    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6775        if self.pending_rename.is_some() {
 6776            return None;
 6777        }
 6778
 6779        let provider = self.semantics_provider.clone()?;
 6780        let buffer = self.buffer.read(cx);
 6781        let newest_selection = self.selections.newest_anchor().clone();
 6782        let cursor_position = newest_selection.head();
 6783        let (cursor_buffer, cursor_buffer_position) =
 6784            buffer.text_anchor_for_position(cursor_position, cx)?;
 6785        let (tail_buffer, tail_buffer_position) =
 6786            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6787        if cursor_buffer != tail_buffer {
 6788            return None;
 6789        }
 6790
 6791        let snapshot = cursor_buffer.read(cx).snapshot();
 6792        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6793        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6794        if start_word_range != end_word_range {
 6795            self.document_highlights_task.take();
 6796            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6797            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6798            return None;
 6799        }
 6800
 6801        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6802        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6803            cx.background_executor()
 6804                .timer(Duration::from_millis(debounce))
 6805                .await;
 6806
 6807            let highlights = if let Some(highlights) = cx
 6808                .update(|cx| {
 6809                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6810                })
 6811                .ok()
 6812                .flatten()
 6813            {
 6814                highlights.await.log_err()
 6815            } else {
 6816                None
 6817            };
 6818
 6819            if let Some(highlights) = highlights {
 6820                this.update(cx, |this, cx| {
 6821                    if this.pending_rename.is_some() {
 6822                        return;
 6823                    }
 6824
 6825                    let buffer = this.buffer.read(cx);
 6826                    if buffer
 6827                        .text_anchor_for_position(cursor_position, cx)
 6828                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6829                    {
 6830                        return;
 6831                    }
 6832
 6833                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6834                    let mut write_ranges = Vec::new();
 6835                    let mut read_ranges = Vec::new();
 6836                    for highlight in highlights {
 6837                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6838                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6839                        {
 6840                            let start = highlight
 6841                                .range
 6842                                .start
 6843                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6844                            let end = highlight
 6845                                .range
 6846                                .end
 6847                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6848                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6849                                continue;
 6850                            }
 6851
 6852                            let range = Anchor {
 6853                                buffer_id: Some(buffer_id),
 6854                                excerpt_id,
 6855                                text_anchor: start,
 6856                                diff_base_anchor: None,
 6857                            }..Anchor {
 6858                                buffer_id: Some(buffer_id),
 6859                                excerpt_id,
 6860                                text_anchor: end,
 6861                                diff_base_anchor: None,
 6862                            };
 6863                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6864                                write_ranges.push(range);
 6865                            } else {
 6866                                read_ranges.push(range);
 6867                            }
 6868                        }
 6869                    }
 6870
 6871                    this.highlight_background::<DocumentHighlightRead>(
 6872                        &read_ranges,
 6873                        |theme| theme.colors().editor_document_highlight_read_background,
 6874                        cx,
 6875                    );
 6876                    this.highlight_background::<DocumentHighlightWrite>(
 6877                        &write_ranges,
 6878                        |theme| theme.colors().editor_document_highlight_write_background,
 6879                        cx,
 6880                    );
 6881                    cx.notify();
 6882                })
 6883                .log_err();
 6884            }
 6885        }));
 6886        None
 6887    }
 6888
 6889    fn prepare_highlight_query_from_selection(
 6890        &mut self,
 6891        cx: &mut Context<Editor>,
 6892    ) -> Option<(String, Range<Anchor>)> {
 6893        if matches!(self.mode, EditorMode::SingleLine) {
 6894            return None;
 6895        }
 6896        if !EditorSettings::get_global(cx).selection_highlight {
 6897            return None;
 6898        }
 6899        if self.selections.count() != 1 || self.selections.line_mode {
 6900            return None;
 6901        }
 6902        let selection = self.selections.newest::<Point>(cx);
 6903        if selection.is_empty() || selection.start.row != selection.end.row {
 6904            return None;
 6905        }
 6906        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6907        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6908        let query = multi_buffer_snapshot
 6909            .text_for_range(selection_anchor_range.clone())
 6910            .collect::<String>();
 6911        if query.trim().is_empty() {
 6912            return None;
 6913        }
 6914        Some((query, selection_anchor_range))
 6915    }
 6916
 6917    fn update_selection_occurrence_highlights(
 6918        &mut self,
 6919        query_text: String,
 6920        query_range: Range<Anchor>,
 6921        multi_buffer_range_to_query: Range<Point>,
 6922        use_debounce: bool,
 6923        window: &mut Window,
 6924        cx: &mut Context<Editor>,
 6925    ) -> Task<()> {
 6926        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6927        cx.spawn_in(window, async move |editor, cx| {
 6928            if use_debounce {
 6929                cx.background_executor()
 6930                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6931                    .await;
 6932            }
 6933            let match_task = cx.background_spawn(async move {
 6934                let buffer_ranges = multi_buffer_snapshot
 6935                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6936                    .into_iter()
 6937                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6938                let mut match_ranges = Vec::new();
 6939                let Ok(regex) = project::search::SearchQuery::text(
 6940                    query_text.clone(),
 6941                    false,
 6942                    false,
 6943                    false,
 6944                    Default::default(),
 6945                    Default::default(),
 6946                    false,
 6947                    None,
 6948                ) else {
 6949                    return Vec::default();
 6950                };
 6951                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6952                    match_ranges.extend(
 6953                        regex
 6954                            .search(buffer_snapshot, Some(search_range.clone()))
 6955                            .await
 6956                            .into_iter()
 6957                            .filter_map(|match_range| {
 6958                                let match_start = buffer_snapshot
 6959                                    .anchor_after(search_range.start + match_range.start);
 6960                                let match_end = buffer_snapshot
 6961                                    .anchor_before(search_range.start + match_range.end);
 6962                                let match_anchor_range = Anchor::range_in_buffer(
 6963                                    excerpt_id,
 6964                                    buffer_snapshot.remote_id(),
 6965                                    match_start..match_end,
 6966                                );
 6967                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6968                            }),
 6969                    );
 6970                }
 6971                match_ranges
 6972            });
 6973            let match_ranges = match_task.await;
 6974            editor
 6975                .update_in(cx, |editor, _, cx| {
 6976                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6977                    if !match_ranges.is_empty() {
 6978                        editor.highlight_background::<SelectedTextHighlight>(
 6979                            &match_ranges,
 6980                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6981                            cx,
 6982                        )
 6983                    }
 6984                })
 6985                .log_err();
 6986        })
 6987    }
 6988
 6989    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6990        struct NewlineFold;
 6991        let type_id = std::any::TypeId::of::<NewlineFold>();
 6992        if !self.mode.is_single_line() {
 6993            return;
 6994        }
 6995        let snapshot = self.snapshot(window, cx);
 6996        if snapshot.buffer_snapshot.max_point().row == 0 {
 6997            return;
 6998        }
 6999        let task = cx.background_spawn(async move {
 7000            let new_newlines = snapshot
 7001                .buffer_chars_at(0)
 7002                .filter_map(|(c, i)| {
 7003                    if c == '\n' {
 7004                        Some(
 7005                            snapshot.buffer_snapshot.anchor_after(i)
 7006                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7007                        )
 7008                    } else {
 7009                        None
 7010                    }
 7011                })
 7012                .collect::<Vec<_>>();
 7013            let existing_newlines = snapshot
 7014                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7015                .filter_map(|fold| {
 7016                    if fold.placeholder.type_tag == Some(type_id) {
 7017                        Some(fold.range.start..fold.range.end)
 7018                    } else {
 7019                        None
 7020                    }
 7021                })
 7022                .collect::<Vec<_>>();
 7023
 7024            (new_newlines, existing_newlines)
 7025        });
 7026        self.folding_newlines = cx.spawn(async move |this, cx| {
 7027            let (new_newlines, existing_newlines) = task.await;
 7028            if new_newlines == existing_newlines {
 7029                return;
 7030            }
 7031            let placeholder = FoldPlaceholder {
 7032                render: Arc::new(move |_, _, cx| {
 7033                    div()
 7034                        .bg(cx.theme().status().hint_background)
 7035                        .border_b_1()
 7036                        .size_full()
 7037                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7038                        .border_color(cx.theme().status().hint)
 7039                        .child("\\n")
 7040                        .into_any()
 7041                }),
 7042                constrain_width: false,
 7043                merge_adjacent: false,
 7044                type_tag: Some(type_id),
 7045            };
 7046            let creases = new_newlines
 7047                .into_iter()
 7048                .map(|range| Crease::simple(range, placeholder.clone()))
 7049                .collect();
 7050            this.update(cx, |this, cx| {
 7051                this.display_map.update(cx, |display_map, cx| {
 7052                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7053                    display_map.fold(creases, cx);
 7054                });
 7055            })
 7056            .ok();
 7057        });
 7058    }
 7059
 7060    fn refresh_selected_text_highlights(
 7061        &mut self,
 7062        on_buffer_edit: bool,
 7063        window: &mut Window,
 7064        cx: &mut Context<Editor>,
 7065    ) {
 7066        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7067        else {
 7068            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7069            self.quick_selection_highlight_task.take();
 7070            self.debounced_selection_highlight_task.take();
 7071            return;
 7072        };
 7073        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7074        if on_buffer_edit
 7075            || self
 7076                .quick_selection_highlight_task
 7077                .as_ref()
 7078                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7079        {
 7080            let multi_buffer_visible_start = self
 7081                .scroll_manager
 7082                .anchor()
 7083                .anchor
 7084                .to_point(&multi_buffer_snapshot);
 7085            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7086                multi_buffer_visible_start
 7087                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7088                Bias::Left,
 7089            );
 7090            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7091            self.quick_selection_highlight_task = Some((
 7092                query_range.clone(),
 7093                self.update_selection_occurrence_highlights(
 7094                    query_text.clone(),
 7095                    query_range.clone(),
 7096                    multi_buffer_visible_range,
 7097                    false,
 7098                    window,
 7099                    cx,
 7100                ),
 7101            ));
 7102        }
 7103        if on_buffer_edit
 7104            || self
 7105                .debounced_selection_highlight_task
 7106                .as_ref()
 7107                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7108        {
 7109            let multi_buffer_start = multi_buffer_snapshot
 7110                .anchor_before(0)
 7111                .to_point(&multi_buffer_snapshot);
 7112            let multi_buffer_end = multi_buffer_snapshot
 7113                .anchor_after(multi_buffer_snapshot.len())
 7114                .to_point(&multi_buffer_snapshot);
 7115            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7116            self.debounced_selection_highlight_task = Some((
 7117                query_range.clone(),
 7118                self.update_selection_occurrence_highlights(
 7119                    query_text,
 7120                    query_range,
 7121                    multi_buffer_full_range,
 7122                    true,
 7123                    window,
 7124                    cx,
 7125                ),
 7126            ));
 7127        }
 7128    }
 7129
 7130    pub fn refresh_edit_prediction(
 7131        &mut self,
 7132        debounce: bool,
 7133        user_requested: bool,
 7134        window: &mut Window,
 7135        cx: &mut Context<Self>,
 7136    ) -> Option<()> {
 7137        if DisableAiSettings::get_global(cx).disable_ai {
 7138            return None;
 7139        }
 7140
 7141        let provider = self.edit_prediction_provider()?;
 7142        let cursor = self.selections.newest_anchor().head();
 7143        let (buffer, cursor_buffer_position) =
 7144            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7145
 7146        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7147            self.discard_edit_prediction(false, cx);
 7148            return None;
 7149        }
 7150
 7151        if !user_requested
 7152            && (!self.should_show_edit_predictions()
 7153                || !self.is_focused(window)
 7154                || buffer.read(cx).is_empty())
 7155        {
 7156            self.discard_edit_prediction(false, cx);
 7157            return None;
 7158        }
 7159
 7160        self.update_visible_edit_prediction(window, cx);
 7161        provider.refresh(
 7162            self.project.clone(),
 7163            buffer,
 7164            cursor_buffer_position,
 7165            debounce,
 7166            cx,
 7167        );
 7168        Some(())
 7169    }
 7170
 7171    fn show_edit_predictions_in_menu(&self) -> bool {
 7172        match self.edit_prediction_settings {
 7173            EditPredictionSettings::Disabled => false,
 7174            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7175        }
 7176    }
 7177
 7178    pub fn edit_predictions_enabled(&self) -> bool {
 7179        match self.edit_prediction_settings {
 7180            EditPredictionSettings::Disabled => false,
 7181            EditPredictionSettings::Enabled { .. } => true,
 7182        }
 7183    }
 7184
 7185    fn edit_prediction_requires_modifier(&self) -> bool {
 7186        match self.edit_prediction_settings {
 7187            EditPredictionSettings::Disabled => false,
 7188            EditPredictionSettings::Enabled {
 7189                preview_requires_modifier,
 7190                ..
 7191            } => preview_requires_modifier,
 7192        }
 7193    }
 7194
 7195    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7196        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7197            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7198            self.discard_edit_prediction(false, cx);
 7199        } else {
 7200            let selection = self.selections.newest_anchor();
 7201            let cursor = selection.head();
 7202
 7203            if let Some((buffer, cursor_buffer_position)) =
 7204                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7205            {
 7206                self.edit_prediction_settings =
 7207                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7208            }
 7209        }
 7210    }
 7211
 7212    fn edit_prediction_settings_at_position(
 7213        &self,
 7214        buffer: &Entity<Buffer>,
 7215        buffer_position: language::Anchor,
 7216        cx: &App,
 7217    ) -> EditPredictionSettings {
 7218        if !self.mode.is_full()
 7219            || !self.show_edit_predictions_override.unwrap_or(true)
 7220            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7221        {
 7222            return EditPredictionSettings::Disabled;
 7223        }
 7224
 7225        let buffer = buffer.read(cx);
 7226
 7227        let file = buffer.file();
 7228
 7229        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7230            return EditPredictionSettings::Disabled;
 7231        };
 7232
 7233        let by_provider = matches!(
 7234            self.menu_edit_predictions_policy,
 7235            MenuEditPredictionsPolicy::ByProvider
 7236        );
 7237
 7238        let show_in_menu = by_provider
 7239            && self
 7240                .edit_prediction_provider
 7241                .as_ref()
 7242                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7243
 7244        let preview_requires_modifier =
 7245            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7246
 7247        EditPredictionSettings::Enabled {
 7248            show_in_menu,
 7249            preview_requires_modifier,
 7250        }
 7251    }
 7252
 7253    fn should_show_edit_predictions(&self) -> bool {
 7254        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7255    }
 7256
 7257    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7258        matches!(
 7259            self.edit_prediction_preview,
 7260            EditPredictionPreview::Active { .. }
 7261        )
 7262    }
 7263
 7264    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7265        let cursor = self.selections.newest_anchor().head();
 7266        if let Some((buffer, cursor_position)) =
 7267            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7268        {
 7269            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7270        } else {
 7271            false
 7272        }
 7273    }
 7274
 7275    pub fn supports_minimap(&self, cx: &App) -> bool {
 7276        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7277    }
 7278
 7279    fn edit_predictions_enabled_in_buffer(
 7280        &self,
 7281        buffer: &Entity<Buffer>,
 7282        buffer_position: language::Anchor,
 7283        cx: &App,
 7284    ) -> bool {
 7285        maybe!({
 7286            if self.read_only(cx) {
 7287                return Some(false);
 7288            }
 7289            let provider = self.edit_prediction_provider()?;
 7290            if !provider.is_enabled(buffer, buffer_position, cx) {
 7291                return Some(false);
 7292            }
 7293            let buffer = buffer.read(cx);
 7294            let Some(file) = buffer.file() else {
 7295                return Some(true);
 7296            };
 7297            let settings = all_language_settings(Some(file), cx);
 7298            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7299        })
 7300        .unwrap_or(false)
 7301    }
 7302
 7303    fn cycle_edit_prediction(
 7304        &mut self,
 7305        direction: Direction,
 7306        window: &mut Window,
 7307        cx: &mut Context<Self>,
 7308    ) -> Option<()> {
 7309        let provider = self.edit_prediction_provider()?;
 7310        let cursor = self.selections.newest_anchor().head();
 7311        let (buffer, cursor_buffer_position) =
 7312            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7313        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7314            return None;
 7315        }
 7316
 7317        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7318        self.update_visible_edit_prediction(window, cx);
 7319
 7320        Some(())
 7321    }
 7322
 7323    pub fn show_edit_prediction(
 7324        &mut self,
 7325        _: &ShowEditPrediction,
 7326        window: &mut Window,
 7327        cx: &mut Context<Self>,
 7328    ) {
 7329        if !self.has_active_edit_prediction() {
 7330            self.refresh_edit_prediction(false, true, window, cx);
 7331            return;
 7332        }
 7333
 7334        self.update_visible_edit_prediction(window, cx);
 7335    }
 7336
 7337    pub fn display_cursor_names(
 7338        &mut self,
 7339        _: &DisplayCursorNames,
 7340        window: &mut Window,
 7341        cx: &mut Context<Self>,
 7342    ) {
 7343        self.show_cursor_names(window, cx);
 7344    }
 7345
 7346    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7347        self.show_cursor_names = true;
 7348        cx.notify();
 7349        cx.spawn_in(window, async move |this, cx| {
 7350            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7351            this.update(cx, |this, cx| {
 7352                this.show_cursor_names = false;
 7353                cx.notify()
 7354            })
 7355            .ok()
 7356        })
 7357        .detach();
 7358    }
 7359
 7360    pub fn next_edit_prediction(
 7361        &mut self,
 7362        _: &NextEditPrediction,
 7363        window: &mut Window,
 7364        cx: &mut Context<Self>,
 7365    ) {
 7366        if self.has_active_edit_prediction() {
 7367            self.cycle_edit_prediction(Direction::Next, window, cx);
 7368        } else {
 7369            let is_copilot_disabled = self
 7370                .refresh_edit_prediction(false, true, window, cx)
 7371                .is_none();
 7372            if is_copilot_disabled {
 7373                cx.propagate();
 7374            }
 7375        }
 7376    }
 7377
 7378    pub fn previous_edit_prediction(
 7379        &mut self,
 7380        _: &PreviousEditPrediction,
 7381        window: &mut Window,
 7382        cx: &mut Context<Self>,
 7383    ) {
 7384        if self.has_active_edit_prediction() {
 7385            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7386        } else {
 7387            let is_copilot_disabled = self
 7388                .refresh_edit_prediction(false, true, window, cx)
 7389                .is_none();
 7390            if is_copilot_disabled {
 7391                cx.propagate();
 7392            }
 7393        }
 7394    }
 7395
 7396    pub fn accept_edit_prediction(
 7397        &mut self,
 7398        _: &AcceptEditPrediction,
 7399        window: &mut Window,
 7400        cx: &mut Context<Self>,
 7401    ) {
 7402        if self.show_edit_predictions_in_menu() {
 7403            self.hide_context_menu(window, cx);
 7404        }
 7405
 7406        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7407            return;
 7408        };
 7409
 7410        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7411
 7412        match &active_edit_prediction.completion {
 7413            EditPrediction::Move { target, .. } => {
 7414                let target = *target;
 7415
 7416                if let Some(position_map) = &self.last_position_map {
 7417                    if position_map
 7418                        .visible_row_range
 7419                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7420                        || !self.edit_prediction_requires_modifier()
 7421                    {
 7422                        self.unfold_ranges(&[target..target], true, false, cx);
 7423                        // Note that this is also done in vim's handler of the Tab action.
 7424                        self.change_selections(
 7425                            SelectionEffects::scroll(Autoscroll::newest()),
 7426                            window,
 7427                            cx,
 7428                            |selections| {
 7429                                selections.select_anchor_ranges([target..target]);
 7430                            },
 7431                        );
 7432                        self.clear_row_highlights::<EditPredictionPreview>();
 7433
 7434                        self.edit_prediction_preview
 7435                            .set_previous_scroll_position(None);
 7436                    } else {
 7437                        self.edit_prediction_preview
 7438                            .set_previous_scroll_position(Some(
 7439                                position_map.snapshot.scroll_anchor,
 7440                            ));
 7441
 7442                        self.highlight_rows::<EditPredictionPreview>(
 7443                            target..target,
 7444                            cx.theme().colors().editor_highlighted_line_background,
 7445                            RowHighlightOptions {
 7446                                autoscroll: true,
 7447                                ..Default::default()
 7448                            },
 7449                            cx,
 7450                        );
 7451                        self.request_autoscroll(Autoscroll::fit(), cx);
 7452                    }
 7453                }
 7454            }
 7455            EditPrediction::Edit { edits, .. } => {
 7456                if let Some(provider) = self.edit_prediction_provider() {
 7457                    provider.accept(cx);
 7458                }
 7459
 7460                // Store the transaction ID and selections before applying the edit
 7461                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7462
 7463                let snapshot = self.buffer.read(cx).snapshot(cx);
 7464                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7465
 7466                self.buffer.update(cx, |buffer, cx| {
 7467                    buffer.edit(edits.iter().cloned(), None, cx)
 7468                });
 7469
 7470                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7471                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7472                });
 7473
 7474                let selections = self.selections.disjoint_anchors_arc();
 7475                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7476                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7477                    if has_new_transaction {
 7478                        self.selection_history
 7479                            .insert_transaction(transaction_id_now, selections);
 7480                    }
 7481                }
 7482
 7483                self.update_visible_edit_prediction(window, cx);
 7484                if self.active_edit_prediction.is_none() {
 7485                    self.refresh_edit_prediction(true, true, window, cx);
 7486                }
 7487
 7488                cx.notify();
 7489            }
 7490        }
 7491
 7492        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7493    }
 7494
 7495    pub fn accept_partial_edit_prediction(
 7496        &mut self,
 7497        _: &AcceptPartialEditPrediction,
 7498        window: &mut Window,
 7499        cx: &mut Context<Self>,
 7500    ) {
 7501        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7502            return;
 7503        };
 7504        if self.selections.count() != 1 {
 7505            return;
 7506        }
 7507
 7508        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7509
 7510        match &active_edit_prediction.completion {
 7511            EditPrediction::Move { target, .. } => {
 7512                let target = *target;
 7513                self.change_selections(
 7514                    SelectionEffects::scroll(Autoscroll::newest()),
 7515                    window,
 7516                    cx,
 7517                    |selections| {
 7518                        selections.select_anchor_ranges([target..target]);
 7519                    },
 7520                );
 7521            }
 7522            EditPrediction::Edit { edits, .. } => {
 7523                // Find an insertion that starts at the cursor position.
 7524                let snapshot = self.buffer.read(cx).snapshot(cx);
 7525                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7526                let insertion = edits.iter().find_map(|(range, text)| {
 7527                    let range = range.to_offset(&snapshot);
 7528                    if range.is_empty() && range.start == cursor_offset {
 7529                        Some(text)
 7530                    } else {
 7531                        None
 7532                    }
 7533                });
 7534
 7535                if let Some(text) = insertion {
 7536                    let mut partial_completion = text
 7537                        .chars()
 7538                        .by_ref()
 7539                        .take_while(|c| c.is_alphabetic())
 7540                        .collect::<String>();
 7541                    if partial_completion.is_empty() {
 7542                        partial_completion = text
 7543                            .chars()
 7544                            .by_ref()
 7545                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7546                            .collect::<String>();
 7547                    }
 7548
 7549                    cx.emit(EditorEvent::InputHandled {
 7550                        utf16_range_to_replace: None,
 7551                        text: partial_completion.clone().into(),
 7552                    });
 7553
 7554                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7555
 7556                    self.refresh_edit_prediction(true, true, window, cx);
 7557                    cx.notify();
 7558                } else {
 7559                    self.accept_edit_prediction(&Default::default(), window, cx);
 7560                }
 7561            }
 7562        }
 7563    }
 7564
 7565    fn discard_edit_prediction(
 7566        &mut self,
 7567        should_report_edit_prediction_event: bool,
 7568        cx: &mut Context<Self>,
 7569    ) -> bool {
 7570        if should_report_edit_prediction_event {
 7571            let completion_id = self
 7572                .active_edit_prediction
 7573                .as_ref()
 7574                .and_then(|active_completion| active_completion.completion_id.clone());
 7575
 7576            self.report_edit_prediction_event(completion_id, false, cx);
 7577        }
 7578
 7579        if let Some(provider) = self.edit_prediction_provider() {
 7580            provider.discard(cx);
 7581        }
 7582
 7583        self.take_active_edit_prediction(cx)
 7584    }
 7585
 7586    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7587        let Some(provider) = self.edit_prediction_provider() else {
 7588            return;
 7589        };
 7590
 7591        let Some((_, buffer, _)) = self
 7592            .buffer
 7593            .read(cx)
 7594            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7595        else {
 7596            return;
 7597        };
 7598
 7599        let extension = buffer
 7600            .read(cx)
 7601            .file()
 7602            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7603
 7604        let event_type = match accepted {
 7605            true => "Edit Prediction Accepted",
 7606            false => "Edit Prediction Discarded",
 7607        };
 7608        telemetry::event!(
 7609            event_type,
 7610            provider = provider.name(),
 7611            prediction_id = id,
 7612            suggestion_accepted = accepted,
 7613            file_extension = extension,
 7614        );
 7615    }
 7616
 7617    pub fn has_active_edit_prediction(&self) -> bool {
 7618        self.active_edit_prediction.is_some()
 7619    }
 7620
 7621    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7622        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7623            return false;
 7624        };
 7625
 7626        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7627        self.clear_highlights::<EditPredictionHighlight>(cx);
 7628        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7629        true
 7630    }
 7631
 7632    /// Returns true when we're displaying the edit prediction popover below the cursor
 7633    /// like we are not previewing and the LSP autocomplete menu is visible
 7634    /// or we are in `when_holding_modifier` mode.
 7635    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7636        if self.edit_prediction_preview_is_active()
 7637            || !self.show_edit_predictions_in_menu()
 7638            || !self.edit_predictions_enabled()
 7639        {
 7640            return false;
 7641        }
 7642
 7643        if self.has_visible_completions_menu() {
 7644            return true;
 7645        }
 7646
 7647        has_completion && self.edit_prediction_requires_modifier()
 7648    }
 7649
 7650    fn handle_modifiers_changed(
 7651        &mut self,
 7652        modifiers: Modifiers,
 7653        position_map: &PositionMap,
 7654        window: &mut Window,
 7655        cx: &mut Context<Self>,
 7656    ) {
 7657        if self.show_edit_predictions_in_menu() {
 7658            self.update_edit_prediction_preview(&modifiers, window, cx);
 7659        }
 7660
 7661        self.update_selection_mode(&modifiers, position_map, window, cx);
 7662
 7663        let mouse_position = window.mouse_position();
 7664        if !position_map.text_hitbox.is_hovered(window) {
 7665            return;
 7666        }
 7667
 7668        self.update_hovered_link(
 7669            position_map.point_for_position(mouse_position),
 7670            &position_map.snapshot,
 7671            modifiers,
 7672            window,
 7673            cx,
 7674        )
 7675    }
 7676
 7677    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7678        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7679        if invert {
 7680            match multi_cursor_setting {
 7681                MultiCursorModifier::Alt => modifiers.alt,
 7682                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7683            }
 7684        } else {
 7685            match multi_cursor_setting {
 7686                MultiCursorModifier::Alt => modifiers.secondary(),
 7687                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7688            }
 7689        }
 7690    }
 7691
 7692    fn columnar_selection_mode(
 7693        modifiers: &Modifiers,
 7694        cx: &mut Context<Self>,
 7695    ) -> Option<ColumnarMode> {
 7696        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7697            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7698                Some(ColumnarMode::FromMouse)
 7699            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7700                Some(ColumnarMode::FromSelection)
 7701            } else {
 7702                None
 7703            }
 7704        } else {
 7705            None
 7706        }
 7707    }
 7708
 7709    fn update_selection_mode(
 7710        &mut self,
 7711        modifiers: &Modifiers,
 7712        position_map: &PositionMap,
 7713        window: &mut Window,
 7714        cx: &mut Context<Self>,
 7715    ) {
 7716        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7717            return;
 7718        };
 7719        if self.selections.pending_anchor().is_none() {
 7720            return;
 7721        }
 7722
 7723        let mouse_position = window.mouse_position();
 7724        let point_for_position = position_map.point_for_position(mouse_position);
 7725        let position = point_for_position.previous_valid;
 7726
 7727        self.select(
 7728            SelectPhase::BeginColumnar {
 7729                position,
 7730                reset: false,
 7731                mode,
 7732                goal_column: point_for_position.exact_unclipped.column(),
 7733            },
 7734            window,
 7735            cx,
 7736        );
 7737    }
 7738
 7739    fn update_edit_prediction_preview(
 7740        &mut self,
 7741        modifiers: &Modifiers,
 7742        window: &mut Window,
 7743        cx: &mut Context<Self>,
 7744    ) {
 7745        let mut modifiers_held = false;
 7746        if let Some(accept_keystroke) = self
 7747            .accept_edit_prediction_keybind(false, window, cx)
 7748            .keystroke()
 7749        {
 7750            modifiers_held = modifiers_held
 7751                || (accept_keystroke.modifiers() == modifiers
 7752                    && accept_keystroke.modifiers().modified());
 7753        };
 7754        if let Some(accept_partial_keystroke) = self
 7755            .accept_edit_prediction_keybind(true, window, cx)
 7756            .keystroke()
 7757        {
 7758            modifiers_held = modifiers_held
 7759                || (accept_partial_keystroke.modifiers() == modifiers
 7760                    && accept_partial_keystroke.modifiers().modified());
 7761        }
 7762
 7763        if modifiers_held {
 7764            if matches!(
 7765                self.edit_prediction_preview,
 7766                EditPredictionPreview::Inactive { .. }
 7767            ) {
 7768                self.edit_prediction_preview = EditPredictionPreview::Active {
 7769                    previous_scroll_position: None,
 7770                    since: Instant::now(),
 7771                };
 7772
 7773                self.update_visible_edit_prediction(window, cx);
 7774                cx.notify();
 7775            }
 7776        } else if let EditPredictionPreview::Active {
 7777            previous_scroll_position,
 7778            since,
 7779        } = self.edit_prediction_preview
 7780        {
 7781            if let (Some(previous_scroll_position), Some(position_map)) =
 7782                (previous_scroll_position, self.last_position_map.as_ref())
 7783            {
 7784                self.set_scroll_position(
 7785                    previous_scroll_position
 7786                        .scroll_position(&position_map.snapshot.display_snapshot),
 7787                    window,
 7788                    cx,
 7789                );
 7790            }
 7791
 7792            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7793                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7794            };
 7795            self.clear_row_highlights::<EditPredictionPreview>();
 7796            self.update_visible_edit_prediction(window, cx);
 7797            cx.notify();
 7798        }
 7799    }
 7800
 7801    fn update_visible_edit_prediction(
 7802        &mut self,
 7803        _window: &mut Window,
 7804        cx: &mut Context<Self>,
 7805    ) -> Option<()> {
 7806        if DisableAiSettings::get_global(cx).disable_ai {
 7807            return None;
 7808        }
 7809
 7810        if self.ime_transaction.is_some() {
 7811            self.discard_edit_prediction(false, cx);
 7812            return None;
 7813        }
 7814
 7815        let selection = self.selections.newest_anchor();
 7816        let cursor = selection.head();
 7817        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7818        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7819        let excerpt_id = cursor.excerpt_id;
 7820
 7821        let show_in_menu = self.show_edit_predictions_in_menu();
 7822        let completions_menu_has_precedence = !show_in_menu
 7823            && (self.context_menu.borrow().is_some()
 7824                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7825
 7826        if completions_menu_has_precedence
 7827            || !offset_selection.is_empty()
 7828            || self
 7829                .active_edit_prediction
 7830                .as_ref()
 7831                .is_some_and(|completion| {
 7832                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7833                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7834                    !invalidation_range.contains(&offset_selection.head())
 7835                })
 7836        {
 7837            self.discard_edit_prediction(false, cx);
 7838            return None;
 7839        }
 7840
 7841        self.take_active_edit_prediction(cx);
 7842        let Some(provider) = self.edit_prediction_provider() else {
 7843            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7844            return None;
 7845        };
 7846
 7847        let (buffer, cursor_buffer_position) =
 7848            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7849
 7850        self.edit_prediction_settings =
 7851            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7852
 7853        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7854            self.discard_edit_prediction(false, cx);
 7855            return None;
 7856        };
 7857
 7858        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7859
 7860        if self.edit_prediction_indent_conflict {
 7861            let cursor_point = cursor.to_point(&multibuffer);
 7862
 7863            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7864
 7865            if let Some((_, indent)) = indents.iter().next()
 7866                && indent.len == cursor_point.column
 7867            {
 7868                self.edit_prediction_indent_conflict = false;
 7869            }
 7870        }
 7871
 7872        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7873        let edits = edit_prediction
 7874            .edits
 7875            .into_iter()
 7876            .flat_map(|(range, new_text)| {
 7877                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7878                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7879                Some((start..end, new_text))
 7880            })
 7881            .collect::<Vec<_>>();
 7882        if edits.is_empty() {
 7883            return None;
 7884        }
 7885
 7886        let first_edit_start = edits.first().unwrap().0.start;
 7887        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7888        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7889
 7890        let last_edit_end = edits.last().unwrap().0.end;
 7891        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7892        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7893
 7894        let cursor_row = cursor.to_point(&multibuffer).row;
 7895
 7896        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7897
 7898        let mut inlay_ids = Vec::new();
 7899        let invalidation_row_range;
 7900        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7901            Some(cursor_row..edit_end_row)
 7902        } else if cursor_row > edit_end_row {
 7903            Some(edit_start_row..cursor_row)
 7904        } else {
 7905            None
 7906        };
 7907        let supports_jump = self
 7908            .edit_prediction_provider
 7909            .as_ref()
 7910            .map(|provider| provider.provider.supports_jump_to_edit())
 7911            .unwrap_or(true);
 7912
 7913        let is_move = supports_jump
 7914            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7915        let completion = if is_move {
 7916            invalidation_row_range =
 7917                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7918            let target = first_edit_start;
 7919            EditPrediction::Move { target, snapshot }
 7920        } else {
 7921            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7922                && !self.edit_predictions_hidden_for_vim_mode;
 7923
 7924            if show_completions_in_buffer {
 7925                if edits
 7926                    .iter()
 7927                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7928                {
 7929                    let mut inlays = Vec::new();
 7930                    for (range, new_text) in &edits {
 7931                        let inlay = Inlay::edit_prediction(
 7932                            post_inc(&mut self.next_inlay_id),
 7933                            range.start,
 7934                            new_text.as_str(),
 7935                        );
 7936                        inlay_ids.push(inlay.id);
 7937                        inlays.push(inlay);
 7938                    }
 7939
 7940                    self.splice_inlays(&[], inlays, cx);
 7941                } else {
 7942                    let background_color = cx.theme().status().deleted_background;
 7943                    self.highlight_text::<EditPredictionHighlight>(
 7944                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7945                        HighlightStyle {
 7946                            background_color: Some(background_color),
 7947                            ..Default::default()
 7948                        },
 7949                        cx,
 7950                    );
 7951                }
 7952            }
 7953
 7954            invalidation_row_range = edit_start_row..edit_end_row;
 7955
 7956            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7957                if provider.show_tab_accept_marker() {
 7958                    EditDisplayMode::TabAccept
 7959                } else {
 7960                    EditDisplayMode::Inline
 7961                }
 7962            } else {
 7963                EditDisplayMode::DiffPopover
 7964            };
 7965
 7966            EditPrediction::Edit {
 7967                edits,
 7968                edit_preview: edit_prediction.edit_preview,
 7969                display_mode,
 7970                snapshot,
 7971            }
 7972        };
 7973
 7974        let invalidation_range = multibuffer
 7975            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7976            ..multibuffer.anchor_after(Point::new(
 7977                invalidation_row_range.end,
 7978                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7979            ));
 7980
 7981        self.stale_edit_prediction_in_menu = None;
 7982        self.active_edit_prediction = Some(EditPredictionState {
 7983            inlay_ids,
 7984            completion,
 7985            completion_id: edit_prediction.id,
 7986            invalidation_range,
 7987        });
 7988
 7989        cx.notify();
 7990
 7991        Some(())
 7992    }
 7993
 7994    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7995        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7996    }
 7997
 7998    fn clear_tasks(&mut self) {
 7999        self.tasks.clear()
 8000    }
 8001
 8002    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8003        if self.tasks.insert(key, value).is_some() {
 8004            // This case should hopefully be rare, but just in case...
 8005            log::error!(
 8006                "multiple different run targets found on a single line, only the last target will be rendered"
 8007            )
 8008        }
 8009    }
 8010
 8011    /// Get all display points of breakpoints that will be rendered within editor
 8012    ///
 8013    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8014    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8015    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8016    fn active_breakpoints(
 8017        &self,
 8018        range: Range<DisplayRow>,
 8019        window: &mut Window,
 8020        cx: &mut Context<Self>,
 8021    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8022        let mut breakpoint_display_points = HashMap::default();
 8023
 8024        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8025            return breakpoint_display_points;
 8026        };
 8027
 8028        let snapshot = self.snapshot(window, cx);
 8029
 8030        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8031        let Some(project) = self.project() else {
 8032            return breakpoint_display_points;
 8033        };
 8034
 8035        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8036            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8037
 8038        for (buffer_snapshot, range, excerpt_id) in
 8039            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8040        {
 8041            let Some(buffer) = project
 8042                .read(cx)
 8043                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8044            else {
 8045                continue;
 8046            };
 8047            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8048                &buffer,
 8049                Some(
 8050                    buffer_snapshot.anchor_before(range.start)
 8051                        ..buffer_snapshot.anchor_after(range.end),
 8052                ),
 8053                buffer_snapshot,
 8054                cx,
 8055            );
 8056            for (breakpoint, state) in breakpoints {
 8057                let multi_buffer_anchor =
 8058                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8059                let position = multi_buffer_anchor
 8060                    .to_point(multi_buffer_snapshot)
 8061                    .to_display_point(&snapshot);
 8062
 8063                breakpoint_display_points.insert(
 8064                    position.row(),
 8065                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8066                );
 8067            }
 8068        }
 8069
 8070        breakpoint_display_points
 8071    }
 8072
 8073    fn breakpoint_context_menu(
 8074        &self,
 8075        anchor: Anchor,
 8076        window: &mut Window,
 8077        cx: &mut Context<Self>,
 8078    ) -> Entity<ui::ContextMenu> {
 8079        let weak_editor = cx.weak_entity();
 8080        let focus_handle = self.focus_handle(cx);
 8081
 8082        let row = self
 8083            .buffer
 8084            .read(cx)
 8085            .snapshot(cx)
 8086            .summary_for_anchor::<Point>(&anchor)
 8087            .row;
 8088
 8089        let breakpoint = self
 8090            .breakpoint_at_row(row, window, cx)
 8091            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8092
 8093        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8094            "Edit Log Breakpoint"
 8095        } else {
 8096            "Set Log Breakpoint"
 8097        };
 8098
 8099        let condition_breakpoint_msg = if breakpoint
 8100            .as_ref()
 8101            .is_some_and(|bp| bp.1.condition.is_some())
 8102        {
 8103            "Edit Condition Breakpoint"
 8104        } else {
 8105            "Set Condition Breakpoint"
 8106        };
 8107
 8108        let hit_condition_breakpoint_msg = if breakpoint
 8109            .as_ref()
 8110            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8111        {
 8112            "Edit Hit Condition Breakpoint"
 8113        } else {
 8114            "Set Hit Condition Breakpoint"
 8115        };
 8116
 8117        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8118            "Unset Breakpoint"
 8119        } else {
 8120            "Set Breakpoint"
 8121        };
 8122
 8123        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8124
 8125        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8126            BreakpointState::Enabled => Some("Disable"),
 8127            BreakpointState::Disabled => Some("Enable"),
 8128        });
 8129
 8130        let (anchor, breakpoint) =
 8131            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8132
 8133        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8134            menu.on_blur_subscription(Subscription::new(|| {}))
 8135                .context(focus_handle)
 8136                .when(run_to_cursor, |this| {
 8137                    let weak_editor = weak_editor.clone();
 8138                    this.entry("Run to cursor", None, move |window, cx| {
 8139                        weak_editor
 8140                            .update(cx, |editor, cx| {
 8141                                editor.change_selections(
 8142                                    SelectionEffects::no_scroll(),
 8143                                    window,
 8144                                    cx,
 8145                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8146                                );
 8147                            })
 8148                            .ok();
 8149
 8150                        window.dispatch_action(Box::new(RunToCursor), cx);
 8151                    })
 8152                    .separator()
 8153                })
 8154                .when_some(toggle_state_msg, |this, msg| {
 8155                    this.entry(msg, None, {
 8156                        let weak_editor = weak_editor.clone();
 8157                        let breakpoint = breakpoint.clone();
 8158                        move |_window, cx| {
 8159                            weak_editor
 8160                                .update(cx, |this, cx| {
 8161                                    this.edit_breakpoint_at_anchor(
 8162                                        anchor,
 8163                                        breakpoint.as_ref().clone(),
 8164                                        BreakpointEditAction::InvertState,
 8165                                        cx,
 8166                                    );
 8167                                })
 8168                                .log_err();
 8169                        }
 8170                    })
 8171                })
 8172                .entry(set_breakpoint_msg, None, {
 8173                    let weak_editor = weak_editor.clone();
 8174                    let breakpoint = breakpoint.clone();
 8175                    move |_window, cx| {
 8176                        weak_editor
 8177                            .update(cx, |this, cx| {
 8178                                this.edit_breakpoint_at_anchor(
 8179                                    anchor,
 8180                                    breakpoint.as_ref().clone(),
 8181                                    BreakpointEditAction::Toggle,
 8182                                    cx,
 8183                                );
 8184                            })
 8185                            .log_err();
 8186                    }
 8187                })
 8188                .entry(log_breakpoint_msg, None, {
 8189                    let breakpoint = breakpoint.clone();
 8190                    let weak_editor = weak_editor.clone();
 8191                    move |window, cx| {
 8192                        weak_editor
 8193                            .update(cx, |this, cx| {
 8194                                this.add_edit_breakpoint_block(
 8195                                    anchor,
 8196                                    breakpoint.as_ref(),
 8197                                    BreakpointPromptEditAction::Log,
 8198                                    window,
 8199                                    cx,
 8200                                );
 8201                            })
 8202                            .log_err();
 8203                    }
 8204                })
 8205                .entry(condition_breakpoint_msg, None, {
 8206                    let breakpoint = breakpoint.clone();
 8207                    let weak_editor = weak_editor.clone();
 8208                    move |window, cx| {
 8209                        weak_editor
 8210                            .update(cx, |this, cx| {
 8211                                this.add_edit_breakpoint_block(
 8212                                    anchor,
 8213                                    breakpoint.as_ref(),
 8214                                    BreakpointPromptEditAction::Condition,
 8215                                    window,
 8216                                    cx,
 8217                                );
 8218                            })
 8219                            .log_err();
 8220                    }
 8221                })
 8222                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8223                    weak_editor
 8224                        .update(cx, |this, cx| {
 8225                            this.add_edit_breakpoint_block(
 8226                                anchor,
 8227                                breakpoint.as_ref(),
 8228                                BreakpointPromptEditAction::HitCondition,
 8229                                window,
 8230                                cx,
 8231                            );
 8232                        })
 8233                        .log_err();
 8234                })
 8235        })
 8236    }
 8237
 8238    fn render_breakpoint(
 8239        &self,
 8240        position: Anchor,
 8241        row: DisplayRow,
 8242        breakpoint: &Breakpoint,
 8243        state: Option<BreakpointSessionState>,
 8244        cx: &mut Context<Self>,
 8245    ) -> IconButton {
 8246        let is_rejected = state.is_some_and(|s| !s.verified);
 8247        // Is it a breakpoint that shows up when hovering over gutter?
 8248        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8249            (false, false),
 8250            |PhantomBreakpointIndicator {
 8251                 is_active,
 8252                 display_row,
 8253                 collides_with_existing_breakpoint,
 8254             }| {
 8255                (
 8256                    is_active && display_row == row,
 8257                    collides_with_existing_breakpoint,
 8258                )
 8259            },
 8260        );
 8261
 8262        let (color, icon) = {
 8263            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8264                (false, false) => ui::IconName::DebugBreakpoint,
 8265                (true, false) => ui::IconName::DebugLogBreakpoint,
 8266                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8267                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8268            };
 8269
 8270            let color = if is_phantom {
 8271                Color::Hint
 8272            } else if is_rejected {
 8273                Color::Disabled
 8274            } else {
 8275                Color::Debugger
 8276            };
 8277
 8278            (color, icon)
 8279        };
 8280
 8281        let breakpoint = Arc::from(breakpoint.clone());
 8282
 8283        let alt_as_text = gpui::Keystroke {
 8284            modifiers: Modifiers::secondary_key(),
 8285            ..Default::default()
 8286        };
 8287        let primary_action_text = if breakpoint.is_disabled() {
 8288            "Enable breakpoint"
 8289        } else if is_phantom && !collides_with_existing {
 8290            "Set breakpoint"
 8291        } else {
 8292            "Unset breakpoint"
 8293        };
 8294        let focus_handle = self.focus_handle.clone();
 8295
 8296        let meta = if is_rejected {
 8297            SharedString::from("No executable code is associated with this line.")
 8298        } else if collides_with_existing && !breakpoint.is_disabled() {
 8299            SharedString::from(format!(
 8300                "{alt_as_text}-click to disable,\nright-click for more options."
 8301            ))
 8302        } else {
 8303            SharedString::from("Right-click for more options.")
 8304        };
 8305        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8306            .icon_size(IconSize::XSmall)
 8307            .size(ui::ButtonSize::None)
 8308            .when(is_rejected, |this| {
 8309                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8310            })
 8311            .icon_color(color)
 8312            .style(ButtonStyle::Transparent)
 8313            .on_click(cx.listener({
 8314                move |editor, event: &ClickEvent, window, cx| {
 8315                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8316                        BreakpointEditAction::InvertState
 8317                    } else {
 8318                        BreakpointEditAction::Toggle
 8319                    };
 8320
 8321                    window.focus(&editor.focus_handle(cx));
 8322                    editor.edit_breakpoint_at_anchor(
 8323                        position,
 8324                        breakpoint.as_ref().clone(),
 8325                        edit_action,
 8326                        cx,
 8327                    );
 8328                }
 8329            }))
 8330            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8331                editor.set_breakpoint_context_menu(
 8332                    row,
 8333                    Some(position),
 8334                    event.position(),
 8335                    window,
 8336                    cx,
 8337                );
 8338            }))
 8339            .tooltip(move |window, cx| {
 8340                Tooltip::with_meta_in(
 8341                    primary_action_text,
 8342                    Some(&ToggleBreakpoint),
 8343                    meta.clone(),
 8344                    &focus_handle,
 8345                    window,
 8346                    cx,
 8347                )
 8348            })
 8349    }
 8350
 8351    fn build_tasks_context(
 8352        project: &Entity<Project>,
 8353        buffer: &Entity<Buffer>,
 8354        buffer_row: u32,
 8355        tasks: &Arc<RunnableTasks>,
 8356        cx: &mut Context<Self>,
 8357    ) -> Task<Option<task::TaskContext>> {
 8358        let position = Point::new(buffer_row, tasks.column);
 8359        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8360        let location = Location {
 8361            buffer: buffer.clone(),
 8362            range: range_start..range_start,
 8363        };
 8364        // Fill in the environmental variables from the tree-sitter captures
 8365        let mut captured_task_variables = TaskVariables::default();
 8366        for (capture_name, value) in tasks.extra_variables.clone() {
 8367            captured_task_variables.insert(
 8368                task::VariableName::Custom(capture_name.into()),
 8369                value.clone(),
 8370            );
 8371        }
 8372        project.update(cx, |project, cx| {
 8373            project.task_store().update(cx, |task_store, cx| {
 8374                task_store.task_context_for_location(captured_task_variables, location, cx)
 8375            })
 8376        })
 8377    }
 8378
 8379    pub fn spawn_nearest_task(
 8380        &mut self,
 8381        action: &SpawnNearestTask,
 8382        window: &mut Window,
 8383        cx: &mut Context<Self>,
 8384    ) {
 8385        let Some((workspace, _)) = self.workspace.clone() else {
 8386            return;
 8387        };
 8388        let Some(project) = self.project.clone() else {
 8389            return;
 8390        };
 8391
 8392        // Try to find a closest, enclosing node using tree-sitter that has a task
 8393        let Some((buffer, buffer_row, tasks)) = self
 8394            .find_enclosing_node_task(cx)
 8395            // Or find the task that's closest in row-distance.
 8396            .or_else(|| self.find_closest_task(cx))
 8397        else {
 8398            return;
 8399        };
 8400
 8401        let reveal_strategy = action.reveal;
 8402        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8403        cx.spawn_in(window, async move |_, cx| {
 8404            let context = task_context.await?;
 8405            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8406
 8407            let resolved = &mut resolved_task.resolved;
 8408            resolved.reveal = reveal_strategy;
 8409
 8410            workspace
 8411                .update_in(cx, |workspace, window, cx| {
 8412                    workspace.schedule_resolved_task(
 8413                        task_source_kind,
 8414                        resolved_task,
 8415                        false,
 8416                        window,
 8417                        cx,
 8418                    );
 8419                })
 8420                .ok()
 8421        })
 8422        .detach();
 8423    }
 8424
 8425    fn find_closest_task(
 8426        &mut self,
 8427        cx: &mut Context<Self>,
 8428    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8429        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8430
 8431        let ((buffer_id, row), tasks) = self
 8432            .tasks
 8433            .iter()
 8434            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8435
 8436        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8437        let tasks = Arc::new(tasks.to_owned());
 8438        Some((buffer, *row, tasks))
 8439    }
 8440
 8441    fn find_enclosing_node_task(
 8442        &mut self,
 8443        cx: &mut Context<Self>,
 8444    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8445        let snapshot = self.buffer.read(cx).snapshot(cx);
 8446        let offset = self.selections.newest::<usize>(cx).head();
 8447        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8448        let buffer_id = excerpt.buffer().remote_id();
 8449
 8450        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8451        let mut cursor = layer.node().walk();
 8452
 8453        while cursor.goto_first_child_for_byte(offset).is_some() {
 8454            if cursor.node().end_byte() == offset {
 8455                cursor.goto_next_sibling();
 8456            }
 8457        }
 8458
 8459        // Ascend to the smallest ancestor that contains the range and has a task.
 8460        loop {
 8461            let node = cursor.node();
 8462            let node_range = node.byte_range();
 8463            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8464
 8465            // Check if this node contains our offset
 8466            if node_range.start <= offset && node_range.end >= offset {
 8467                // If it contains offset, check for task
 8468                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8469                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8470                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8471                }
 8472            }
 8473
 8474            if !cursor.goto_parent() {
 8475                break;
 8476            }
 8477        }
 8478        None
 8479    }
 8480
 8481    fn render_run_indicator(
 8482        &self,
 8483        _style: &EditorStyle,
 8484        is_active: bool,
 8485        row: DisplayRow,
 8486        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8487        cx: &mut Context<Self>,
 8488    ) -> IconButton {
 8489        let color = Color::Muted;
 8490        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8491
 8492        IconButton::new(
 8493            ("run_indicator", row.0 as usize),
 8494            ui::IconName::PlayOutlined,
 8495        )
 8496        .shape(ui::IconButtonShape::Square)
 8497        .icon_size(IconSize::XSmall)
 8498        .icon_color(color)
 8499        .toggle_state(is_active)
 8500        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8501            let quick_launch = match e {
 8502                ClickEvent::Keyboard(_) => true,
 8503                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8504            };
 8505
 8506            window.focus(&editor.focus_handle(cx));
 8507            editor.toggle_code_actions(
 8508                &ToggleCodeActions {
 8509                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8510                    quick_launch,
 8511                },
 8512                window,
 8513                cx,
 8514            );
 8515        }))
 8516        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8517            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8518        }))
 8519    }
 8520
 8521    pub fn context_menu_visible(&self) -> bool {
 8522        !self.edit_prediction_preview_is_active()
 8523            && self
 8524                .context_menu
 8525                .borrow()
 8526                .as_ref()
 8527                .is_some_and(|menu| menu.visible())
 8528    }
 8529
 8530    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8531        self.context_menu
 8532            .borrow()
 8533            .as_ref()
 8534            .map(|menu| menu.origin())
 8535    }
 8536
 8537    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8538        self.context_menu_options = Some(options);
 8539    }
 8540
 8541    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8542    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8543
 8544    fn render_edit_prediction_popover(
 8545        &mut self,
 8546        text_bounds: &Bounds<Pixels>,
 8547        content_origin: gpui::Point<Pixels>,
 8548        right_margin: Pixels,
 8549        editor_snapshot: &EditorSnapshot,
 8550        visible_row_range: Range<DisplayRow>,
 8551        scroll_top: f32,
 8552        scroll_bottom: f32,
 8553        line_layouts: &[LineWithInvisibles],
 8554        line_height: Pixels,
 8555        scroll_pixel_position: gpui::Point<Pixels>,
 8556        newest_selection_head: Option<DisplayPoint>,
 8557        editor_width: Pixels,
 8558        style: &EditorStyle,
 8559        window: &mut Window,
 8560        cx: &mut App,
 8561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8562        if self.mode().is_minimap() {
 8563            return None;
 8564        }
 8565        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8566
 8567        if self.edit_prediction_visible_in_cursor_popover(true) {
 8568            return None;
 8569        }
 8570
 8571        match &active_edit_prediction.completion {
 8572            EditPrediction::Move { target, .. } => {
 8573                let target_display_point = target.to_display_point(editor_snapshot);
 8574
 8575                if self.edit_prediction_requires_modifier() {
 8576                    if !self.edit_prediction_preview_is_active() {
 8577                        return None;
 8578                    }
 8579
 8580                    self.render_edit_prediction_modifier_jump_popover(
 8581                        text_bounds,
 8582                        content_origin,
 8583                        visible_row_range,
 8584                        line_layouts,
 8585                        line_height,
 8586                        scroll_pixel_position,
 8587                        newest_selection_head,
 8588                        target_display_point,
 8589                        window,
 8590                        cx,
 8591                    )
 8592                } else {
 8593                    self.render_edit_prediction_eager_jump_popover(
 8594                        text_bounds,
 8595                        content_origin,
 8596                        editor_snapshot,
 8597                        visible_row_range,
 8598                        scroll_top,
 8599                        scroll_bottom,
 8600                        line_height,
 8601                        scroll_pixel_position,
 8602                        target_display_point,
 8603                        editor_width,
 8604                        window,
 8605                        cx,
 8606                    )
 8607                }
 8608            }
 8609            EditPrediction::Edit {
 8610                display_mode: EditDisplayMode::Inline,
 8611                ..
 8612            } => None,
 8613            EditPrediction::Edit {
 8614                display_mode: EditDisplayMode::TabAccept,
 8615                edits,
 8616                ..
 8617            } => {
 8618                let range = &edits.first()?.0;
 8619                let target_display_point = range.end.to_display_point(editor_snapshot);
 8620
 8621                self.render_edit_prediction_end_of_line_popover(
 8622                    "Accept",
 8623                    editor_snapshot,
 8624                    visible_row_range,
 8625                    target_display_point,
 8626                    line_height,
 8627                    scroll_pixel_position,
 8628                    content_origin,
 8629                    editor_width,
 8630                    window,
 8631                    cx,
 8632                )
 8633            }
 8634            EditPrediction::Edit {
 8635                edits,
 8636                edit_preview,
 8637                display_mode: EditDisplayMode::DiffPopover,
 8638                snapshot,
 8639            } => self.render_edit_prediction_diff_popover(
 8640                text_bounds,
 8641                content_origin,
 8642                right_margin,
 8643                editor_snapshot,
 8644                visible_row_range,
 8645                line_layouts,
 8646                line_height,
 8647                scroll_pixel_position,
 8648                newest_selection_head,
 8649                editor_width,
 8650                style,
 8651                edits,
 8652                edit_preview,
 8653                snapshot,
 8654                window,
 8655                cx,
 8656            ),
 8657        }
 8658    }
 8659
 8660    fn render_edit_prediction_modifier_jump_popover(
 8661        &mut self,
 8662        text_bounds: &Bounds<Pixels>,
 8663        content_origin: gpui::Point<Pixels>,
 8664        visible_row_range: Range<DisplayRow>,
 8665        line_layouts: &[LineWithInvisibles],
 8666        line_height: Pixels,
 8667        scroll_pixel_position: gpui::Point<Pixels>,
 8668        newest_selection_head: Option<DisplayPoint>,
 8669        target_display_point: DisplayPoint,
 8670        window: &mut Window,
 8671        cx: &mut App,
 8672    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8673        let scrolled_content_origin =
 8674            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8675
 8676        const SCROLL_PADDING_Y: Pixels = px(12.);
 8677
 8678        if target_display_point.row() < visible_row_range.start {
 8679            return self.render_edit_prediction_scroll_popover(
 8680                |_| SCROLL_PADDING_Y,
 8681                IconName::ArrowUp,
 8682                visible_row_range,
 8683                line_layouts,
 8684                newest_selection_head,
 8685                scrolled_content_origin,
 8686                window,
 8687                cx,
 8688            );
 8689        } else if target_display_point.row() >= visible_row_range.end {
 8690            return self.render_edit_prediction_scroll_popover(
 8691                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8692                IconName::ArrowDown,
 8693                visible_row_range,
 8694                line_layouts,
 8695                newest_selection_head,
 8696                scrolled_content_origin,
 8697                window,
 8698                cx,
 8699            );
 8700        }
 8701
 8702        const POLE_WIDTH: Pixels = px(2.);
 8703
 8704        let line_layout =
 8705            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8706        let target_column = target_display_point.column() as usize;
 8707
 8708        let target_x = line_layout.x_for_index(target_column);
 8709        let target_y =
 8710            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8711
 8712        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8713
 8714        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8715        border_color.l += 0.001;
 8716
 8717        let mut element = v_flex()
 8718            .items_end()
 8719            .when(flag_on_right, |el| el.items_start())
 8720            .child(if flag_on_right {
 8721                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8722                    .rounded_bl(px(0.))
 8723                    .rounded_tl(px(0.))
 8724                    .border_l_2()
 8725                    .border_color(border_color)
 8726            } else {
 8727                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8728                    .rounded_br(px(0.))
 8729                    .rounded_tr(px(0.))
 8730                    .border_r_2()
 8731                    .border_color(border_color)
 8732            })
 8733            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8734            .into_any();
 8735
 8736        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8737
 8738        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8739            - point(
 8740                if flag_on_right {
 8741                    POLE_WIDTH
 8742                } else {
 8743                    size.width - POLE_WIDTH
 8744                },
 8745                size.height - line_height,
 8746            );
 8747
 8748        origin.x = origin.x.max(content_origin.x);
 8749
 8750        element.prepaint_at(origin, window, cx);
 8751
 8752        Some((element, origin))
 8753    }
 8754
 8755    fn render_edit_prediction_scroll_popover(
 8756        &mut self,
 8757        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8758        scroll_icon: IconName,
 8759        visible_row_range: Range<DisplayRow>,
 8760        line_layouts: &[LineWithInvisibles],
 8761        newest_selection_head: Option<DisplayPoint>,
 8762        scrolled_content_origin: gpui::Point<Pixels>,
 8763        window: &mut Window,
 8764        cx: &mut App,
 8765    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8766        let mut element = self
 8767            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8768            .into_any();
 8769
 8770        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8771
 8772        let cursor = newest_selection_head?;
 8773        let cursor_row_layout =
 8774            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8775        let cursor_column = cursor.column() as usize;
 8776
 8777        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8778
 8779        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8780
 8781        element.prepaint_at(origin, window, cx);
 8782        Some((element, origin))
 8783    }
 8784
 8785    fn render_edit_prediction_eager_jump_popover(
 8786        &mut self,
 8787        text_bounds: &Bounds<Pixels>,
 8788        content_origin: gpui::Point<Pixels>,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        scroll_top: f32,
 8792        scroll_bottom: f32,
 8793        line_height: Pixels,
 8794        scroll_pixel_position: gpui::Point<Pixels>,
 8795        target_display_point: DisplayPoint,
 8796        editor_width: Pixels,
 8797        window: &mut Window,
 8798        cx: &mut App,
 8799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8800        if target_display_point.row().as_f32() < scroll_top {
 8801            let mut element = self
 8802                .render_edit_prediction_line_popover(
 8803                    "Jump to Edit",
 8804                    Some(IconName::ArrowUp),
 8805                    window,
 8806                    cx,
 8807                )?
 8808                .into_any();
 8809
 8810            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8811            let offset = point(
 8812                (text_bounds.size.width - size.width) / 2.,
 8813                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8814            );
 8815
 8816            let origin = text_bounds.origin + offset;
 8817            element.prepaint_at(origin, window, cx);
 8818            Some((element, origin))
 8819        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8820            let mut element = self
 8821                .render_edit_prediction_line_popover(
 8822                    "Jump to Edit",
 8823                    Some(IconName::ArrowDown),
 8824                    window,
 8825                    cx,
 8826                )?
 8827                .into_any();
 8828
 8829            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830            let offset = point(
 8831                (text_bounds.size.width - size.width) / 2.,
 8832                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8833            );
 8834
 8835            let origin = text_bounds.origin + offset;
 8836            element.prepaint_at(origin, window, cx);
 8837            Some((element, origin))
 8838        } else {
 8839            self.render_edit_prediction_end_of_line_popover(
 8840                "Jump to Edit",
 8841                editor_snapshot,
 8842                visible_row_range,
 8843                target_display_point,
 8844                line_height,
 8845                scroll_pixel_position,
 8846                content_origin,
 8847                editor_width,
 8848                window,
 8849                cx,
 8850            )
 8851        }
 8852    }
 8853
 8854    fn render_edit_prediction_end_of_line_popover(
 8855        self: &mut Editor,
 8856        label: &'static str,
 8857        editor_snapshot: &EditorSnapshot,
 8858        visible_row_range: Range<DisplayRow>,
 8859        target_display_point: DisplayPoint,
 8860        line_height: Pixels,
 8861        scroll_pixel_position: gpui::Point<Pixels>,
 8862        content_origin: gpui::Point<Pixels>,
 8863        editor_width: Pixels,
 8864        window: &mut Window,
 8865        cx: &mut App,
 8866    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8867        let target_line_end = DisplayPoint::new(
 8868            target_display_point.row(),
 8869            editor_snapshot.line_len(target_display_point.row()),
 8870        );
 8871
 8872        let mut element = self
 8873            .render_edit_prediction_line_popover(label, None, window, cx)?
 8874            .into_any();
 8875
 8876        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877
 8878        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8879
 8880        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8881        let mut origin = start_point
 8882            + line_origin
 8883            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8884        origin.x = origin.x.max(content_origin.x);
 8885
 8886        let max_x = content_origin.x + editor_width - size.width;
 8887
 8888        if origin.x > max_x {
 8889            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8890
 8891            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8892                origin.y += offset;
 8893                IconName::ArrowUp
 8894            } else {
 8895                origin.y -= offset;
 8896                IconName::ArrowDown
 8897            };
 8898
 8899            element = self
 8900                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8901                .into_any();
 8902
 8903            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8904
 8905            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8906        }
 8907
 8908        element.prepaint_at(origin, window, cx);
 8909        Some((element, origin))
 8910    }
 8911
 8912    fn render_edit_prediction_diff_popover(
 8913        self: &Editor,
 8914        text_bounds: &Bounds<Pixels>,
 8915        content_origin: gpui::Point<Pixels>,
 8916        right_margin: Pixels,
 8917        editor_snapshot: &EditorSnapshot,
 8918        visible_row_range: Range<DisplayRow>,
 8919        line_layouts: &[LineWithInvisibles],
 8920        line_height: Pixels,
 8921        scroll_pixel_position: gpui::Point<Pixels>,
 8922        newest_selection_head: Option<DisplayPoint>,
 8923        editor_width: Pixels,
 8924        style: &EditorStyle,
 8925        edits: &Vec<(Range<Anchor>, String)>,
 8926        edit_preview: &Option<language::EditPreview>,
 8927        snapshot: &language::BufferSnapshot,
 8928        window: &mut Window,
 8929        cx: &mut App,
 8930    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8931        let edit_start = edits
 8932            .first()
 8933            .unwrap()
 8934            .0
 8935            .start
 8936            .to_display_point(editor_snapshot);
 8937        let edit_end = edits
 8938            .last()
 8939            .unwrap()
 8940            .0
 8941            .end
 8942            .to_display_point(editor_snapshot);
 8943
 8944        let is_visible = visible_row_range.contains(&edit_start.row())
 8945            || visible_row_range.contains(&edit_end.row());
 8946        if !is_visible {
 8947            return None;
 8948        }
 8949
 8950        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8951            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8952        } else {
 8953            // Fallback for providers without edit_preview
 8954            crate::edit_prediction_fallback_text(edits, cx)
 8955        };
 8956
 8957        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8958        let line_count = highlighted_edits.text.lines().count();
 8959
 8960        const BORDER_WIDTH: Pixels = px(1.);
 8961
 8962        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8963        let has_keybind = keybind.is_some();
 8964
 8965        let mut element = h_flex()
 8966            .items_start()
 8967            .child(
 8968                h_flex()
 8969                    .bg(cx.theme().colors().editor_background)
 8970                    .border(BORDER_WIDTH)
 8971                    .shadow_xs()
 8972                    .border_color(cx.theme().colors().border)
 8973                    .rounded_l_lg()
 8974                    .when(line_count > 1, |el| el.rounded_br_lg())
 8975                    .pr_1()
 8976                    .child(styled_text),
 8977            )
 8978            .child(
 8979                h_flex()
 8980                    .h(line_height + BORDER_WIDTH * 2.)
 8981                    .px_1p5()
 8982                    .gap_1()
 8983                    // Workaround: For some reason, there's a gap if we don't do this
 8984                    .ml(-BORDER_WIDTH)
 8985                    .shadow(vec![gpui::BoxShadow {
 8986                        color: gpui::black().opacity(0.05),
 8987                        offset: point(px(1.), px(1.)),
 8988                        blur_radius: px(2.),
 8989                        spread_radius: px(0.),
 8990                    }])
 8991                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8992                    .border(BORDER_WIDTH)
 8993                    .border_color(cx.theme().colors().border)
 8994                    .rounded_r_lg()
 8995                    .id("edit_prediction_diff_popover_keybind")
 8996                    .when(!has_keybind, |el| {
 8997                        let status_colors = cx.theme().status();
 8998
 8999                        el.bg(status_colors.error_background)
 9000                            .border_color(status_colors.error.opacity(0.6))
 9001                            .child(Icon::new(IconName::Info).color(Color::Error))
 9002                            .cursor_default()
 9003                            .hoverable_tooltip(move |_window, cx| {
 9004                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9005                            })
 9006                    })
 9007                    .children(keybind),
 9008            )
 9009            .into_any();
 9010
 9011        let longest_row =
 9012            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9013        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9014            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9015        } else {
 9016            layout_line(
 9017                longest_row,
 9018                editor_snapshot,
 9019                style,
 9020                editor_width,
 9021                |_| false,
 9022                window,
 9023                cx,
 9024            )
 9025            .width
 9026        };
 9027
 9028        let viewport_bounds =
 9029            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9030                right: -right_margin,
 9031                ..Default::default()
 9032            });
 9033
 9034        let x_after_longest =
 9035            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9036                - scroll_pixel_position.x;
 9037
 9038        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9039
 9040        // Fully visible if it can be displayed within the window (allow overlapping other
 9041        // panes). However, this is only allowed if the popover starts within text_bounds.
 9042        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9043            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9044
 9045        let mut origin = if can_position_to_the_right {
 9046            point(
 9047                x_after_longest,
 9048                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9049                    - scroll_pixel_position.y,
 9050            )
 9051        } else {
 9052            let cursor_row = newest_selection_head.map(|head| head.row());
 9053            let above_edit = edit_start
 9054                .row()
 9055                .0
 9056                .checked_sub(line_count as u32)
 9057                .map(DisplayRow);
 9058            let below_edit = Some(edit_end.row() + 1);
 9059            let above_cursor =
 9060                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9061            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9062
 9063            // Place the edit popover adjacent to the edit if there is a location
 9064            // available that is onscreen and does not obscure the cursor. Otherwise,
 9065            // place it adjacent to the cursor.
 9066            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9067                .into_iter()
 9068                .flatten()
 9069                .find(|&start_row| {
 9070                    let end_row = start_row + line_count as u32;
 9071                    visible_row_range.contains(&start_row)
 9072                        && visible_row_range.contains(&end_row)
 9073                        && cursor_row
 9074                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9075                })?;
 9076
 9077            content_origin
 9078                + point(
 9079                    -scroll_pixel_position.x,
 9080                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9081                )
 9082        };
 9083
 9084        origin.x -= BORDER_WIDTH;
 9085
 9086        window.defer_draw(element, origin, 1);
 9087
 9088        // Do not return an element, since it will already be drawn due to defer_draw.
 9089        None
 9090    }
 9091
 9092    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9093        px(30.)
 9094    }
 9095
 9096    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9097        if self.read_only(cx) {
 9098            cx.theme().players().read_only()
 9099        } else {
 9100            self.style.as_ref().unwrap().local_player
 9101        }
 9102    }
 9103
 9104    fn render_edit_prediction_accept_keybind(
 9105        &self,
 9106        window: &mut Window,
 9107        cx: &App,
 9108    ) -> Option<AnyElement> {
 9109        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9110        let accept_keystroke = accept_binding.keystroke()?;
 9111
 9112        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9113
 9114        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9115            Color::Accent
 9116        } else {
 9117            Color::Muted
 9118        };
 9119
 9120        h_flex()
 9121            .px_0p5()
 9122            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9123            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9124            .text_size(TextSize::XSmall.rems(cx))
 9125            .child(h_flex().children(ui::render_modifiers(
 9126                accept_keystroke.modifiers(),
 9127                PlatformStyle::platform(),
 9128                Some(modifiers_color),
 9129                Some(IconSize::XSmall.rems().into()),
 9130                true,
 9131            )))
 9132            .when(is_platform_style_mac, |parent| {
 9133                parent.child(accept_keystroke.key().to_string())
 9134            })
 9135            .when(!is_platform_style_mac, |parent| {
 9136                parent.child(
 9137                    Key::new(
 9138                        util::capitalize(accept_keystroke.key()),
 9139                        Some(Color::Default),
 9140                    )
 9141                    .size(Some(IconSize::XSmall.rems().into())),
 9142                )
 9143            })
 9144            .into_any()
 9145            .into()
 9146    }
 9147
 9148    fn render_edit_prediction_line_popover(
 9149        &self,
 9150        label: impl Into<SharedString>,
 9151        icon: Option<IconName>,
 9152        window: &mut Window,
 9153        cx: &App,
 9154    ) -> Option<Stateful<Div>> {
 9155        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9156
 9157        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9158        let has_keybind = keybind.is_some();
 9159
 9160        let result = h_flex()
 9161            .id("ep-line-popover")
 9162            .py_0p5()
 9163            .pl_1()
 9164            .pr(padding_right)
 9165            .gap_1()
 9166            .rounded_md()
 9167            .border_1()
 9168            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9169            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9170            .shadow_xs()
 9171            .when(!has_keybind, |el| {
 9172                let status_colors = cx.theme().status();
 9173
 9174                el.bg(status_colors.error_background)
 9175                    .border_color(status_colors.error.opacity(0.6))
 9176                    .pl_2()
 9177                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9178                    .cursor_default()
 9179                    .hoverable_tooltip(move |_window, cx| {
 9180                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9181                    })
 9182            })
 9183            .children(keybind)
 9184            .child(
 9185                Label::new(label)
 9186                    .size(LabelSize::Small)
 9187                    .when(!has_keybind, |el| {
 9188                        el.color(cx.theme().status().error.into()).strikethrough()
 9189                    }),
 9190            )
 9191            .when(!has_keybind, |el| {
 9192                el.child(
 9193                    h_flex().ml_1().child(
 9194                        Icon::new(IconName::Info)
 9195                            .size(IconSize::Small)
 9196                            .color(cx.theme().status().error.into()),
 9197                    ),
 9198                )
 9199            })
 9200            .when_some(icon, |element, icon| {
 9201                element.child(
 9202                    div()
 9203                        .mt(px(1.5))
 9204                        .child(Icon::new(icon).size(IconSize::Small)),
 9205                )
 9206            });
 9207
 9208        Some(result)
 9209    }
 9210
 9211    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9212        let accent_color = cx.theme().colors().text_accent;
 9213        let editor_bg_color = cx.theme().colors().editor_background;
 9214        editor_bg_color.blend(accent_color.opacity(0.1))
 9215    }
 9216
 9217    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9218        let accent_color = cx.theme().colors().text_accent;
 9219        let editor_bg_color = cx.theme().colors().editor_background;
 9220        editor_bg_color.blend(accent_color.opacity(0.6))
 9221    }
 9222    fn get_prediction_provider_icon_name(
 9223        provider: &Option<RegisteredEditPredictionProvider>,
 9224    ) -> IconName {
 9225        match provider {
 9226            Some(provider) => match provider.provider.name() {
 9227                "copilot" => IconName::Copilot,
 9228                "supermaven" => IconName::Supermaven,
 9229                _ => IconName::ZedPredict,
 9230            },
 9231            None => IconName::ZedPredict,
 9232        }
 9233    }
 9234
 9235    fn render_edit_prediction_cursor_popover(
 9236        &self,
 9237        min_width: Pixels,
 9238        max_width: Pixels,
 9239        cursor_point: Point,
 9240        style: &EditorStyle,
 9241        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9242        _window: &Window,
 9243        cx: &mut Context<Editor>,
 9244    ) -> Option<AnyElement> {
 9245        let provider = self.edit_prediction_provider.as_ref()?;
 9246        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9247
 9248        let is_refreshing = provider.provider.is_refreshing(cx);
 9249
 9250        fn pending_completion_container(icon: IconName) -> Div {
 9251            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9252        }
 9253
 9254        let completion = match &self.active_edit_prediction {
 9255            Some(prediction) => {
 9256                if !self.has_visible_completions_menu() {
 9257                    const RADIUS: Pixels = px(6.);
 9258                    const BORDER_WIDTH: Pixels = px(1.);
 9259
 9260                    return Some(
 9261                        h_flex()
 9262                            .elevation_2(cx)
 9263                            .border(BORDER_WIDTH)
 9264                            .border_color(cx.theme().colors().border)
 9265                            .when(accept_keystroke.is_none(), |el| {
 9266                                el.border_color(cx.theme().status().error)
 9267                            })
 9268                            .rounded(RADIUS)
 9269                            .rounded_tl(px(0.))
 9270                            .overflow_hidden()
 9271                            .child(div().px_1p5().child(match &prediction.completion {
 9272                                EditPrediction::Move { target, snapshot } => {
 9273                                    use text::ToPoint as _;
 9274                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9275                                    {
 9276                                        Icon::new(IconName::ZedPredictDown)
 9277                                    } else {
 9278                                        Icon::new(IconName::ZedPredictUp)
 9279                                    }
 9280                                }
 9281                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9282                            }))
 9283                            .child(
 9284                                h_flex()
 9285                                    .gap_1()
 9286                                    .py_1()
 9287                                    .px_2()
 9288                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9289                                    .border_l_1()
 9290                                    .border_color(cx.theme().colors().border)
 9291                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9292                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9293                                        el.child(
 9294                                            Label::new("Hold")
 9295                                                .size(LabelSize::Small)
 9296                                                .when(accept_keystroke.is_none(), |el| {
 9297                                                    el.strikethrough()
 9298                                                })
 9299                                                .line_height_style(LineHeightStyle::UiLabel),
 9300                                        )
 9301                                    })
 9302                                    .id("edit_prediction_cursor_popover_keybind")
 9303                                    .when(accept_keystroke.is_none(), |el| {
 9304                                        let status_colors = cx.theme().status();
 9305
 9306                                        el.bg(status_colors.error_background)
 9307                                            .border_color(status_colors.error.opacity(0.6))
 9308                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9309                                            .cursor_default()
 9310                                            .hoverable_tooltip(move |_window, cx| {
 9311                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9312                                                    .into()
 9313                                            })
 9314                                    })
 9315                                    .when_some(
 9316                                        accept_keystroke.as_ref(),
 9317                                        |el, accept_keystroke| {
 9318                                            el.child(h_flex().children(ui::render_modifiers(
 9319                                                accept_keystroke.modifiers(),
 9320                                                PlatformStyle::platform(),
 9321                                                Some(Color::Default),
 9322                                                Some(IconSize::XSmall.rems().into()),
 9323                                                false,
 9324                                            )))
 9325                                        },
 9326                                    ),
 9327                            )
 9328                            .into_any(),
 9329                    );
 9330                }
 9331
 9332                self.render_edit_prediction_cursor_popover_preview(
 9333                    prediction,
 9334                    cursor_point,
 9335                    style,
 9336                    cx,
 9337                )?
 9338            }
 9339
 9340            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9341                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9342                    stale_completion,
 9343                    cursor_point,
 9344                    style,
 9345                    cx,
 9346                )?,
 9347
 9348                None => pending_completion_container(provider_icon)
 9349                    .child(Label::new("...").size(LabelSize::Small)),
 9350            },
 9351
 9352            None => pending_completion_container(provider_icon)
 9353                .child(Label::new("...").size(LabelSize::Small)),
 9354        };
 9355
 9356        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9357            completion
 9358                .with_animation(
 9359                    "loading-completion",
 9360                    Animation::new(Duration::from_secs(2))
 9361                        .repeat()
 9362                        .with_easing(pulsating_between(0.4, 0.8)),
 9363                    |label, delta| label.opacity(delta),
 9364                )
 9365                .into_any_element()
 9366        } else {
 9367            completion.into_any_element()
 9368        };
 9369
 9370        let has_completion = self.active_edit_prediction.is_some();
 9371
 9372        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9373        Some(
 9374            h_flex()
 9375                .min_w(min_width)
 9376                .max_w(max_width)
 9377                .flex_1()
 9378                .elevation_2(cx)
 9379                .border_color(cx.theme().colors().border)
 9380                .child(
 9381                    div()
 9382                        .flex_1()
 9383                        .py_1()
 9384                        .px_2()
 9385                        .overflow_hidden()
 9386                        .child(completion),
 9387                )
 9388                .when_some(accept_keystroke, |el, accept_keystroke| {
 9389                    if !accept_keystroke.modifiers().modified() {
 9390                        return el;
 9391                    }
 9392
 9393                    el.child(
 9394                        h_flex()
 9395                            .h_full()
 9396                            .border_l_1()
 9397                            .rounded_r_lg()
 9398                            .border_color(cx.theme().colors().border)
 9399                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9400                            .gap_1()
 9401                            .py_1()
 9402                            .px_2()
 9403                            .child(
 9404                                h_flex()
 9405                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9406                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9407                                    .child(h_flex().children(ui::render_modifiers(
 9408                                        accept_keystroke.modifiers(),
 9409                                        PlatformStyle::platform(),
 9410                                        Some(if !has_completion {
 9411                                            Color::Muted
 9412                                        } else {
 9413                                            Color::Default
 9414                                        }),
 9415                                        None,
 9416                                        false,
 9417                                    ))),
 9418                            )
 9419                            .child(Label::new("Preview").into_any_element())
 9420                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9421                    )
 9422                })
 9423                .into_any(),
 9424        )
 9425    }
 9426
 9427    fn render_edit_prediction_cursor_popover_preview(
 9428        &self,
 9429        completion: &EditPredictionState,
 9430        cursor_point: Point,
 9431        style: &EditorStyle,
 9432        cx: &mut Context<Editor>,
 9433    ) -> Option<Div> {
 9434        use text::ToPoint as _;
 9435
 9436        fn render_relative_row_jump(
 9437            prefix: impl Into<String>,
 9438            current_row: u32,
 9439            target_row: u32,
 9440        ) -> Div {
 9441            let (row_diff, arrow) = if target_row < current_row {
 9442                (current_row - target_row, IconName::ArrowUp)
 9443            } else {
 9444                (target_row - current_row, IconName::ArrowDown)
 9445            };
 9446
 9447            h_flex()
 9448                .child(
 9449                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9450                        .color(Color::Muted)
 9451                        .size(LabelSize::Small),
 9452                )
 9453                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9454        }
 9455
 9456        let supports_jump = self
 9457            .edit_prediction_provider
 9458            .as_ref()
 9459            .map(|provider| provider.provider.supports_jump_to_edit())
 9460            .unwrap_or(true);
 9461
 9462        match &completion.completion {
 9463            EditPrediction::Move {
 9464                target, snapshot, ..
 9465            } => {
 9466                if !supports_jump {
 9467                    return None;
 9468                }
 9469
 9470                Some(
 9471                    h_flex()
 9472                        .px_2()
 9473                        .gap_2()
 9474                        .flex_1()
 9475                        .child(
 9476                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9477                                Icon::new(IconName::ZedPredictDown)
 9478                            } else {
 9479                                Icon::new(IconName::ZedPredictUp)
 9480                            },
 9481                        )
 9482                        .child(Label::new("Jump to Edit")),
 9483                )
 9484            }
 9485
 9486            EditPrediction::Edit {
 9487                edits,
 9488                edit_preview,
 9489                snapshot,
 9490                display_mode: _,
 9491            } => {
 9492                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9493
 9494                let (highlighted_edits, has_more_lines) =
 9495                    if let Some(edit_preview) = edit_preview.as_ref() {
 9496                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9497                            .first_line_preview()
 9498                    } else {
 9499                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9500                    };
 9501
 9502                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9503                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9504
 9505                let preview = h_flex()
 9506                    .gap_1()
 9507                    .min_w_16()
 9508                    .child(styled_text)
 9509                    .when(has_more_lines, |parent| parent.child(""));
 9510
 9511                let left = if supports_jump && first_edit_row != cursor_point.row {
 9512                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9513                        .into_any_element()
 9514                } else {
 9515                    let icon_name =
 9516                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9517                    Icon::new(icon_name).into_any_element()
 9518                };
 9519
 9520                Some(
 9521                    h_flex()
 9522                        .h_full()
 9523                        .flex_1()
 9524                        .gap_2()
 9525                        .pr_1()
 9526                        .overflow_x_hidden()
 9527                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9528                        .child(left)
 9529                        .child(preview),
 9530                )
 9531            }
 9532        }
 9533    }
 9534
 9535    pub fn render_context_menu(
 9536        &self,
 9537        style: &EditorStyle,
 9538        max_height_in_lines: u32,
 9539        window: &mut Window,
 9540        cx: &mut Context<Editor>,
 9541    ) -> Option<AnyElement> {
 9542        let menu = self.context_menu.borrow();
 9543        let menu = menu.as_ref()?;
 9544        if !menu.visible() {
 9545            return None;
 9546        };
 9547        Some(menu.render(style, max_height_in_lines, window, cx))
 9548    }
 9549
 9550    fn render_context_menu_aside(
 9551        &mut self,
 9552        max_size: Size<Pixels>,
 9553        window: &mut Window,
 9554        cx: &mut Context<Editor>,
 9555    ) -> Option<AnyElement> {
 9556        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9557            if menu.visible() {
 9558                menu.render_aside(max_size, window, cx)
 9559            } else {
 9560                None
 9561            }
 9562        })
 9563    }
 9564
 9565    fn hide_context_menu(
 9566        &mut self,
 9567        window: &mut Window,
 9568        cx: &mut Context<Self>,
 9569    ) -> Option<CodeContextMenu> {
 9570        cx.notify();
 9571        self.completion_tasks.clear();
 9572        let context_menu = self.context_menu.borrow_mut().take();
 9573        self.stale_edit_prediction_in_menu.take();
 9574        self.update_visible_edit_prediction(window, cx);
 9575        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9576            && let Some(completion_provider) = &self.completion_provider
 9577        {
 9578            completion_provider.selection_changed(None, window, cx);
 9579        }
 9580        context_menu
 9581    }
 9582
 9583    fn show_snippet_choices(
 9584        &mut self,
 9585        choices: &Vec<String>,
 9586        selection: Range<Anchor>,
 9587        cx: &mut Context<Self>,
 9588    ) {
 9589        let Some((_, buffer, _)) = self
 9590            .buffer()
 9591            .read(cx)
 9592            .excerpt_containing(selection.start, cx)
 9593        else {
 9594            return;
 9595        };
 9596        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9597        else {
 9598            return;
 9599        };
 9600        if buffer != end_buffer {
 9601            log::error!("expected anchor range to have matching buffer IDs");
 9602            return;
 9603        }
 9604
 9605        let id = post_inc(&mut self.next_completion_id);
 9606        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9607        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9608            CompletionsMenu::new_snippet_choices(
 9609                id,
 9610                true,
 9611                choices,
 9612                selection,
 9613                buffer,
 9614                snippet_sort_order,
 9615            ),
 9616        ));
 9617    }
 9618
 9619    pub fn insert_snippet(
 9620        &mut self,
 9621        insertion_ranges: &[Range<usize>],
 9622        snippet: Snippet,
 9623        window: &mut Window,
 9624        cx: &mut Context<Self>,
 9625    ) -> Result<()> {
 9626        struct Tabstop<T> {
 9627            is_end_tabstop: bool,
 9628            ranges: Vec<Range<T>>,
 9629            choices: Option<Vec<String>>,
 9630        }
 9631
 9632        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9633            let snippet_text: Arc<str> = snippet.text.clone().into();
 9634            let edits = insertion_ranges
 9635                .iter()
 9636                .cloned()
 9637                .map(|range| (range, snippet_text.clone()));
 9638            let autoindent_mode = AutoindentMode::Block {
 9639                original_indent_columns: Vec::new(),
 9640            };
 9641            buffer.edit(edits, Some(autoindent_mode), cx);
 9642
 9643            let snapshot = &*buffer.read(cx);
 9644            let snippet = &snippet;
 9645            snippet
 9646                .tabstops
 9647                .iter()
 9648                .map(|tabstop| {
 9649                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9650                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9651                    });
 9652                    let mut tabstop_ranges = tabstop
 9653                        .ranges
 9654                        .iter()
 9655                        .flat_map(|tabstop_range| {
 9656                            let mut delta = 0_isize;
 9657                            insertion_ranges.iter().map(move |insertion_range| {
 9658                                let insertion_start = insertion_range.start as isize + delta;
 9659                                delta +=
 9660                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9661
 9662                                let start = ((insertion_start + tabstop_range.start) as usize)
 9663                                    .min(snapshot.len());
 9664                                let end = ((insertion_start + tabstop_range.end) as usize)
 9665                                    .min(snapshot.len());
 9666                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9667                            })
 9668                        })
 9669                        .collect::<Vec<_>>();
 9670                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9671
 9672                    Tabstop {
 9673                        is_end_tabstop,
 9674                        ranges: tabstop_ranges,
 9675                        choices: tabstop.choices.clone(),
 9676                    }
 9677                })
 9678                .collect::<Vec<_>>()
 9679        });
 9680        if let Some(tabstop) = tabstops.first() {
 9681            self.change_selections(Default::default(), window, cx, |s| {
 9682                // Reverse order so that the first range is the newest created selection.
 9683                // Completions will use it and autoscroll will prioritize it.
 9684                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9685            });
 9686
 9687            if let Some(choices) = &tabstop.choices
 9688                && let Some(selection) = tabstop.ranges.first()
 9689            {
 9690                self.show_snippet_choices(choices, selection.clone(), cx)
 9691            }
 9692
 9693            // If we're already at the last tabstop and it's at the end of the snippet,
 9694            // we're done, we don't need to keep the state around.
 9695            if !tabstop.is_end_tabstop {
 9696                let choices = tabstops
 9697                    .iter()
 9698                    .map(|tabstop| tabstop.choices.clone())
 9699                    .collect();
 9700
 9701                let ranges = tabstops
 9702                    .into_iter()
 9703                    .map(|tabstop| tabstop.ranges)
 9704                    .collect::<Vec<_>>();
 9705
 9706                self.snippet_stack.push(SnippetState {
 9707                    active_index: 0,
 9708                    ranges,
 9709                    choices,
 9710                });
 9711            }
 9712
 9713            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9714            if self.autoclose_regions.is_empty() {
 9715                let snapshot = self.buffer.read(cx).snapshot(cx);
 9716                let mut all_selections = self.selections.all::<Point>(cx);
 9717                for selection in &mut all_selections {
 9718                    let selection_head = selection.head();
 9719                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9720                        continue;
 9721                    };
 9722
 9723                    let mut bracket_pair = None;
 9724                    let max_lookup_length = scope
 9725                        .brackets()
 9726                        .map(|(pair, _)| {
 9727                            pair.start
 9728                                .as_str()
 9729                                .chars()
 9730                                .count()
 9731                                .max(pair.end.as_str().chars().count())
 9732                        })
 9733                        .max();
 9734                    if let Some(max_lookup_length) = max_lookup_length {
 9735                        let next_text = snapshot
 9736                            .chars_at(selection_head)
 9737                            .take(max_lookup_length)
 9738                            .collect::<String>();
 9739                        let prev_text = snapshot
 9740                            .reversed_chars_at(selection_head)
 9741                            .take(max_lookup_length)
 9742                            .collect::<String>();
 9743
 9744                        for (pair, enabled) in scope.brackets() {
 9745                            if enabled
 9746                                && pair.close
 9747                                && prev_text.starts_with(pair.start.as_str())
 9748                                && next_text.starts_with(pair.end.as_str())
 9749                            {
 9750                                bracket_pair = Some(pair.clone());
 9751                                break;
 9752                            }
 9753                        }
 9754                    }
 9755
 9756                    if let Some(pair) = bracket_pair {
 9757                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9758                        let autoclose_enabled =
 9759                            self.use_autoclose && snapshot_settings.use_autoclose;
 9760                        if autoclose_enabled {
 9761                            let start = snapshot.anchor_after(selection_head);
 9762                            let end = snapshot.anchor_after(selection_head);
 9763                            self.autoclose_regions.push(AutocloseRegion {
 9764                                selection_id: selection.id,
 9765                                range: start..end,
 9766                                pair,
 9767                            });
 9768                        }
 9769                    }
 9770                }
 9771            }
 9772        }
 9773        Ok(())
 9774    }
 9775
 9776    pub fn move_to_next_snippet_tabstop(
 9777        &mut self,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) -> bool {
 9781        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9782    }
 9783
 9784    pub fn move_to_prev_snippet_tabstop(
 9785        &mut self,
 9786        window: &mut Window,
 9787        cx: &mut Context<Self>,
 9788    ) -> bool {
 9789        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9790    }
 9791
 9792    pub fn move_to_snippet_tabstop(
 9793        &mut self,
 9794        bias: Bias,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) -> bool {
 9798        if let Some(mut snippet) = self.snippet_stack.pop() {
 9799            match bias {
 9800                Bias::Left => {
 9801                    if snippet.active_index > 0 {
 9802                        snippet.active_index -= 1;
 9803                    } else {
 9804                        self.snippet_stack.push(snippet);
 9805                        return false;
 9806                    }
 9807                }
 9808                Bias::Right => {
 9809                    if snippet.active_index + 1 < snippet.ranges.len() {
 9810                        snippet.active_index += 1;
 9811                    } else {
 9812                        self.snippet_stack.push(snippet);
 9813                        return false;
 9814                    }
 9815                }
 9816            }
 9817            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9818                self.change_selections(Default::default(), window, cx, |s| {
 9819                    // Reverse order so that the first range is the newest created selection.
 9820                    // Completions will use it and autoscroll will prioritize it.
 9821                    s.select_ranges(current_ranges.iter().rev().cloned())
 9822                });
 9823
 9824                if let Some(choices) = &snippet.choices[snippet.active_index]
 9825                    && let Some(selection) = current_ranges.first()
 9826                {
 9827                    self.show_snippet_choices(choices, selection.clone(), cx);
 9828                }
 9829
 9830                // If snippet state is not at the last tabstop, push it back on the stack
 9831                if snippet.active_index + 1 < snippet.ranges.len() {
 9832                    self.snippet_stack.push(snippet);
 9833                }
 9834                return true;
 9835            }
 9836        }
 9837
 9838        false
 9839    }
 9840
 9841    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9842        self.transact(window, cx, |this, window, cx| {
 9843            this.select_all(&SelectAll, window, cx);
 9844            this.insert("", window, cx);
 9845        });
 9846    }
 9847
 9848    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9849        if self.read_only(cx) {
 9850            return;
 9851        }
 9852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.select_autoclose_pair(window, cx);
 9855            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9856            if !this.linked_edit_ranges.is_empty() {
 9857                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9858                let snapshot = this.buffer.read(cx).snapshot(cx);
 9859
 9860                for selection in selections.iter() {
 9861                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9862                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9863                    if selection_start.buffer_id != selection_end.buffer_id {
 9864                        continue;
 9865                    }
 9866                    if let Some(ranges) =
 9867                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9868                    {
 9869                        for (buffer, entries) in ranges {
 9870                            linked_ranges.entry(buffer).or_default().extend(entries);
 9871                        }
 9872                    }
 9873                }
 9874            }
 9875
 9876            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9877            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9878            for selection in &mut selections {
 9879                if selection.is_empty() {
 9880                    let old_head = selection.head();
 9881                    let mut new_head =
 9882                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9883                            .to_point(&display_map);
 9884                    if let Some((buffer, line_buffer_range)) = display_map
 9885                        .buffer_snapshot
 9886                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9887                    {
 9888                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9889                        let indent_len = match indent_size.kind {
 9890                            IndentKind::Space => {
 9891                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9892                            }
 9893                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9894                        };
 9895                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9896                            let indent_len = indent_len.get();
 9897                            new_head = cmp::min(
 9898                                new_head,
 9899                                MultiBufferPoint::new(
 9900                                    old_head.row,
 9901                                    ((old_head.column - 1) / indent_len) * indent_len,
 9902                                ),
 9903                            );
 9904                        }
 9905                    }
 9906
 9907                    selection.set_head(new_head, SelectionGoal::None);
 9908                }
 9909            }
 9910
 9911            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9912            this.insert("", window, cx);
 9913            let empty_str: Arc<str> = Arc::from("");
 9914            for (buffer, edits) in linked_ranges {
 9915                let snapshot = buffer.read(cx).snapshot();
 9916                use text::ToPoint as TP;
 9917
 9918                let edits = edits
 9919                    .into_iter()
 9920                    .map(|range| {
 9921                        let end_point = TP::to_point(&range.end, &snapshot);
 9922                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9923
 9924                        if end_point == start_point {
 9925                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9926                                .saturating_sub(1);
 9927                            start_point =
 9928                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9929                        };
 9930
 9931                        (start_point..end_point, empty_str.clone())
 9932                    })
 9933                    .sorted_by_key(|(range, _)| range.start)
 9934                    .collect::<Vec<_>>();
 9935                buffer.update(cx, |this, cx| {
 9936                    this.edit(edits, None, cx);
 9937                })
 9938            }
 9939            this.refresh_edit_prediction(true, false, window, cx);
 9940            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.change_selections(Default::default(), window, cx, |s| {
 9951                s.move_with(|map, selection| {
 9952                    if selection.is_empty() {
 9953                        let cursor = movement::right(map, selection.head());
 9954                        selection.end = cursor;
 9955                        selection.reversed = true;
 9956                        selection.goal = SelectionGoal::None;
 9957                    }
 9958                })
 9959            });
 9960            this.insert("", window, cx);
 9961            this.refresh_edit_prediction(true, false, window, cx);
 9962        });
 9963    }
 9964
 9965    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9966        if self.mode.is_single_line() {
 9967            cx.propagate();
 9968            return;
 9969        }
 9970
 9971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9972        if self.move_to_prev_snippet_tabstop(window, cx) {
 9973            return;
 9974        }
 9975        self.outdent(&Outdent, window, cx);
 9976    }
 9977
 9978    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9979        if self.mode.is_single_line() {
 9980            cx.propagate();
 9981            return;
 9982        }
 9983
 9984        if self.move_to_next_snippet_tabstop(window, cx) {
 9985            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9986            return;
 9987        }
 9988        if self.read_only(cx) {
 9989            return;
 9990        }
 9991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9992        let mut selections = self.selections.all_adjusted(cx);
 9993        let buffer = self.buffer.read(cx);
 9994        let snapshot = buffer.snapshot(cx);
 9995        let rows_iter = selections.iter().map(|s| s.head().row);
 9996        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9997
 9998        let has_some_cursor_in_whitespace = selections
 9999            .iter()
10000            .filter(|selection| selection.is_empty())
10001            .any(|selection| {
10002                let cursor = selection.head();
10003                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10004                cursor.column < current_indent.len
10005            });
10006
10007        let mut edits = Vec::new();
10008        let mut prev_edited_row = 0;
10009        let mut row_delta = 0;
10010        for selection in &mut selections {
10011            if selection.start.row != prev_edited_row {
10012                row_delta = 0;
10013            }
10014            prev_edited_row = selection.end.row;
10015
10016            // If the selection is non-empty, then increase the indentation of the selected lines.
10017            if !selection.is_empty() {
10018                row_delta =
10019                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10020                continue;
10021            }
10022
10023            let cursor = selection.head();
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10025            if let Some(suggested_indent) =
10026                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10027            {
10028                // Don't do anything if already at suggested indent
10029                // and there is any other cursor which is not
10030                if has_some_cursor_in_whitespace
10031                    && cursor.column == current_indent.len
10032                    && current_indent.len == suggested_indent.len
10033                {
10034                    continue;
10035                }
10036
10037                // Adjust line and move cursor to suggested indent
10038                // if cursor is not at suggested indent
10039                if cursor.column < suggested_indent.len
10040                    && cursor.column <= current_indent.len
10041                    && current_indent.len <= suggested_indent.len
10042                {
10043                    selection.start = Point::new(cursor.row, suggested_indent.len);
10044                    selection.end = selection.start;
10045                    if row_delta == 0 {
10046                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10047                            cursor.row,
10048                            current_indent,
10049                            suggested_indent,
10050                        ));
10051                        row_delta = suggested_indent.len - current_indent.len;
10052                    }
10053                    continue;
10054                }
10055
10056                // If current indent is more than suggested indent
10057                // only move cursor to current indent and skip indent
10058                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10059                    selection.start = Point::new(cursor.row, current_indent.len);
10060                    selection.end = selection.start;
10061                    continue;
10062                }
10063            }
10064
10065            // Otherwise, insert a hard or soft tab.
10066            let settings = buffer.language_settings_at(cursor, cx);
10067            let tab_size = if settings.hard_tabs {
10068                IndentSize::tab()
10069            } else {
10070                let tab_size = settings.tab_size.get();
10071                let indent_remainder = snapshot
10072                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10073                    .flat_map(str::chars)
10074                    .fold(row_delta % tab_size, |counter: u32, c| {
10075                        if c == '\t' {
10076                            0
10077                        } else {
10078                            (counter + 1) % tab_size
10079                        }
10080                    });
10081
10082                let chars_to_next_tab_stop = tab_size - indent_remainder;
10083                IndentSize::spaces(chars_to_next_tab_stop)
10084            };
10085            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10086            selection.end = selection.start;
10087            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10088            row_delta += tab_size.len;
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10093            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10094            this.refresh_edit_prediction(true, false, window, cx);
10095        });
10096    }
10097
10098    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.read_only(cx) {
10100            return;
10101        }
10102        if self.mode.is_single_line() {
10103            cx.propagate();
10104            return;
10105        }
10106
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        let mut selections = self.selections.all::<Point>(cx);
10109        let mut prev_edited_row = 0;
10110        let mut row_delta = 0;
10111        let mut edits = Vec::new();
10112        let buffer = self.buffer.read(cx);
10113        let snapshot = buffer.snapshot(cx);
10114        for selection in &mut selections {
10115            if selection.start.row != prev_edited_row {
10116                row_delta = 0;
10117            }
10118            prev_edited_row = selection.end.row;
10119
10120            row_delta =
10121                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10122        }
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10126            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10127        });
10128    }
10129
10130    fn indent_selection(
10131        buffer: &MultiBuffer,
10132        snapshot: &MultiBufferSnapshot,
10133        selection: &mut Selection<Point>,
10134        edits: &mut Vec<(Range<Point>, String)>,
10135        delta_for_start_row: u32,
10136        cx: &App,
10137    ) -> u32 {
10138        let settings = buffer.language_settings_at(selection.start, cx);
10139        let tab_size = settings.tab_size.get();
10140        let indent_kind = if settings.hard_tabs {
10141            IndentKind::Tab
10142        } else {
10143            IndentKind::Space
10144        };
10145        let mut start_row = selection.start.row;
10146        let mut end_row = selection.end.row + 1;
10147
10148        // If a selection ends at the beginning of a line, don't indent
10149        // that last line.
10150        if selection.end.column == 0 && selection.end.row > selection.start.row {
10151            end_row -= 1;
10152        }
10153
10154        // Avoid re-indenting a row that has already been indented by a
10155        // previous selection, but still update this selection's column
10156        // to reflect that indentation.
10157        if delta_for_start_row > 0 {
10158            start_row += 1;
10159            selection.start.column += delta_for_start_row;
10160            if selection.end.row == selection.start.row {
10161                selection.end.column += delta_for_start_row;
10162            }
10163        }
10164
10165        let mut delta_for_end_row = 0;
10166        let has_multiple_rows = start_row + 1 != end_row;
10167        for row in start_row..end_row {
10168            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10169            let indent_delta = match (current_indent.kind, indent_kind) {
10170                (IndentKind::Space, IndentKind::Space) => {
10171                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10172                    IndentSize::spaces(columns_to_next_tab_stop)
10173                }
10174                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10175                (_, IndentKind::Tab) => IndentSize::tab(),
10176            };
10177
10178            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10179                0
10180            } else {
10181                selection.start.column
10182            };
10183            let row_start = Point::new(row, start);
10184            edits.push((
10185                row_start..row_start,
10186                indent_delta.chars().collect::<String>(),
10187            ));
10188
10189            // Update this selection's endpoints to reflect the indentation.
10190            if row == selection.start.row {
10191                selection.start.column += indent_delta.len;
10192            }
10193            if row == selection.end.row {
10194                selection.end.column += indent_delta.len;
10195                delta_for_end_row = indent_delta.len;
10196            }
10197        }
10198
10199        if selection.start.row == selection.end.row {
10200            delta_for_start_row + delta_for_end_row
10201        } else {
10202            delta_for_end_row
10203        }
10204    }
10205
10206    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        if self.mode.is_single_line() {
10211            cx.propagate();
10212            return;
10213        }
10214
10215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10216        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10217        let selections = self.selections.all::<Point>(cx);
10218        let mut deletion_ranges = Vec::new();
10219        let mut last_outdent = None;
10220        {
10221            let buffer = self.buffer.read(cx);
10222            let snapshot = buffer.snapshot(cx);
10223            for selection in &selections {
10224                let settings = buffer.language_settings_at(selection.start, cx);
10225                let tab_size = settings.tab_size.get();
10226                let mut rows = selection.spanned_rows(false, &display_map);
10227
10228                // Avoid re-outdenting a row that has already been outdented by a
10229                // previous selection.
10230                if let Some(last_row) = last_outdent
10231                    && last_row == rows.start
10232                {
10233                    rows.start = rows.start.next_row();
10234                }
10235                let has_multiple_rows = rows.len() > 1;
10236                for row in rows.iter_rows() {
10237                    let indent_size = snapshot.indent_size_for_line(row);
10238                    if indent_size.len > 0 {
10239                        let deletion_len = match indent_size.kind {
10240                            IndentKind::Space => {
10241                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10242                                if columns_to_prev_tab_stop == 0 {
10243                                    tab_size
10244                                } else {
10245                                    columns_to_prev_tab_stop
10246                                }
10247                            }
10248                            IndentKind::Tab => 1,
10249                        };
10250                        let start = if has_multiple_rows
10251                            || deletion_len > selection.start.column
10252                            || indent_size.len < selection.start.column
10253                        {
10254                            0
10255                        } else {
10256                            selection.start.column - deletion_len
10257                        };
10258                        deletion_ranges.push(
10259                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10260                        );
10261                        last_outdent = Some(row);
10262                    }
10263                }
10264            }
10265        }
10266
10267        self.transact(window, cx, |this, window, cx| {
10268            this.buffer.update(cx, |buffer, cx| {
10269                let empty_str: Arc<str> = Arc::default();
10270                buffer.edit(
10271                    deletion_ranges
10272                        .into_iter()
10273                        .map(|range| (range, empty_str.clone())),
10274                    None,
10275                    cx,
10276                );
10277            });
10278            let selections = this.selections.all::<usize>(cx);
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10284        if self.read_only(cx) {
10285            return;
10286        }
10287        if self.mode.is_single_line() {
10288            cx.propagate();
10289            return;
10290        }
10291
10292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10293        let selections = self
10294            .selections
10295            .all::<usize>(cx)
10296            .into_iter()
10297            .map(|s| s.range());
10298
10299        self.transact(window, cx, |this, window, cx| {
10300            this.buffer.update(cx, |buffer, cx| {
10301                buffer.autoindent_ranges(selections, cx);
10302            });
10303            let selections = this.selections.all::<usize>(cx);
10304            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10305        });
10306    }
10307
10308    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10311        let selections = self.selections.all::<Point>(cx);
10312
10313        let mut new_cursors = Vec::new();
10314        let mut edit_ranges = Vec::new();
10315        let mut selections = selections.iter().peekable();
10316        while let Some(selection) = selections.next() {
10317            let mut rows = selection.spanned_rows(false, &display_map);
10318            let goal_display_column = selection.head().to_display_point(&display_map).column();
10319
10320            // Accumulate contiguous regions of rows that we want to delete.
10321            while let Some(next_selection) = selections.peek() {
10322                let next_rows = next_selection.spanned_rows(false, &display_map);
10323                if next_rows.start <= rows.end {
10324                    rows.end = next_rows.end;
10325                    selections.next().unwrap();
10326                } else {
10327                    break;
10328                }
10329            }
10330
10331            let buffer = &display_map.buffer_snapshot;
10332            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10333            let edit_end;
10334            let cursor_buffer_row;
10335            if buffer.max_point().row >= rows.end.0 {
10336                // If there's a line after the range, delete the \n from the end of the row range
10337                // and position the cursor on the next line.
10338                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10339                cursor_buffer_row = rows.end;
10340            } else {
10341                // If there isn't a line after the range, delete the \n from the line before the
10342                // start of the row range and position the cursor there.
10343                edit_start = edit_start.saturating_sub(1);
10344                edit_end = buffer.len();
10345                cursor_buffer_row = rows.start.previous_row();
10346            }
10347
10348            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10349            *cursor.column_mut() =
10350                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10351
10352            new_cursors.push((
10353                selection.id,
10354                buffer.anchor_after(cursor.to_point(&display_map)),
10355            ));
10356            edit_ranges.push(edit_start..edit_end);
10357        }
10358
10359        self.transact(window, cx, |this, window, cx| {
10360            let buffer = this.buffer.update(cx, |buffer, cx| {
10361                let empty_str: Arc<str> = Arc::default();
10362                buffer.edit(
10363                    edit_ranges
10364                        .into_iter()
10365                        .map(|range| (range, empty_str.clone())),
10366                    None,
10367                    cx,
10368                );
10369                buffer.snapshot(cx)
10370            });
10371            let new_selections = new_cursors
10372                .into_iter()
10373                .map(|(id, cursor)| {
10374                    let cursor = cursor.to_point(&buffer);
10375                    Selection {
10376                        id,
10377                        start: cursor,
10378                        end: cursor,
10379                        reversed: false,
10380                        goal: SelectionGoal::None,
10381                    }
10382                })
10383                .collect();
10384
10385            this.change_selections(Default::default(), window, cx, |s| {
10386                s.select(new_selections);
10387            });
10388        });
10389    }
10390
10391    pub fn join_lines_impl(
10392        &mut self,
10393        insert_whitespace: bool,
10394        window: &mut Window,
10395        cx: &mut Context<Self>,
10396    ) {
10397        if self.read_only(cx) {
10398            return;
10399        }
10400        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10401        for selection in self.selections.all::<Point>(cx) {
10402            let start = MultiBufferRow(selection.start.row);
10403            // Treat single line selections as if they include the next line. Otherwise this action
10404            // would do nothing for single line selections individual cursors.
10405            let end = if selection.start.row == selection.end.row {
10406                MultiBufferRow(selection.start.row + 1)
10407            } else {
10408                MultiBufferRow(selection.end.row)
10409            };
10410
10411            if let Some(last_row_range) = row_ranges.last_mut()
10412                && start <= last_row_range.end
10413            {
10414                last_row_range.end = end;
10415                continue;
10416            }
10417            row_ranges.push(start..end);
10418        }
10419
10420        let snapshot = self.buffer.read(cx).snapshot(cx);
10421        let mut cursor_positions = Vec::new();
10422        for row_range in &row_ranges {
10423            let anchor = snapshot.anchor_before(Point::new(
10424                row_range.end.previous_row().0,
10425                snapshot.line_len(row_range.end.previous_row()),
10426            ));
10427            cursor_positions.push(anchor..anchor);
10428        }
10429
10430        self.transact(window, cx, |this, window, cx| {
10431            for row_range in row_ranges.into_iter().rev() {
10432                for row in row_range.iter_rows().rev() {
10433                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10434                    let next_line_row = row.next_row();
10435                    let indent = snapshot.indent_size_for_line(next_line_row);
10436                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10437
10438                    let replace =
10439                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10440                            " "
10441                        } else {
10442                            ""
10443                        };
10444
10445                    this.buffer.update(cx, |buffer, cx| {
10446                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10447                    });
10448                }
10449            }
10450
10451            this.change_selections(Default::default(), window, cx, |s| {
10452                s.select_anchor_ranges(cursor_positions)
10453            });
10454        });
10455    }
10456
10457    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459        self.join_lines_impl(true, window, cx);
10460    }
10461
10462    pub fn sort_lines_case_sensitive(
10463        &mut self,
10464        _: &SortLinesCaseSensitive,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10469    }
10470
10471    pub fn sort_lines_by_length(
10472        &mut self,
10473        _: &SortLinesByLength,
10474        window: &mut Window,
10475        cx: &mut Context<Self>,
10476    ) {
10477        self.manipulate_immutable_lines(window, cx, |lines| {
10478            lines.sort_by_key(|&line| line.chars().count())
10479        })
10480    }
10481
10482    pub fn sort_lines_case_insensitive(
10483        &mut self,
10484        _: &SortLinesCaseInsensitive,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| {
10489            lines.sort_by_key(|line| line.to_lowercase())
10490        })
10491    }
10492
10493    pub fn unique_lines_case_insensitive(
10494        &mut self,
10495        _: &UniqueLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            let mut seen = HashSet::default();
10501            lines.retain(|line| seen.insert(line.to_lowercase()));
10502        })
10503    }
10504
10505    pub fn unique_lines_case_sensitive(
10506        &mut self,
10507        _: &UniqueLinesCaseSensitive,
10508        window: &mut Window,
10509        cx: &mut Context<Self>,
10510    ) {
10511        self.manipulate_immutable_lines(window, cx, |lines| {
10512            let mut seen = HashSet::default();
10513            lines.retain(|line| seen.insert(*line));
10514        })
10515    }
10516
10517    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10518        let snapshot = self.buffer.read(cx).snapshot(cx);
10519        for selection in self.selections.disjoint_anchors_arc().iter() {
10520            if snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.as_ref())
10523                .is_some()
10524            {
10525                return true;
10526            }
10527        }
10528        false
10529    }
10530
10531    fn wrap_selections_in_tag(
10532        &mut self,
10533        _: &WrapSelectionsInTag,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) {
10537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10538
10539        let snapshot = self.buffer.read(cx).snapshot(cx);
10540
10541        let mut edits = Vec::new();
10542        let mut boundaries = Vec::new();
10543
10544        for selection in self.selections.all::<Point>(cx).iter() {
10545            let Some(wrap_config) = snapshot
10546                .language_at(selection.start)
10547                .and_then(|lang| lang.config().wrap_characters.clone())
10548            else {
10549                continue;
10550            };
10551
10552            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10553            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10554
10555            let start_before = snapshot.anchor_before(selection.start);
10556            let end_after = snapshot.anchor_after(selection.end);
10557
10558            edits.push((start_before..start_before, open_tag));
10559            edits.push((end_after..end_after, close_tag));
10560
10561            boundaries.push((
10562                start_before,
10563                end_after,
10564                wrap_config.start_prefix.len(),
10565                wrap_config.end_suffix.len(),
10566            ));
10567        }
10568
10569        if edits.is_empty() {
10570            return;
10571        }
10572
10573        self.transact(window, cx, |this, window, cx| {
10574            let buffer = this.buffer.update(cx, |buffer, cx| {
10575                buffer.edit(edits, None, cx);
10576                buffer.snapshot(cx)
10577            });
10578
10579            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10580            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10581                boundaries.into_iter()
10582            {
10583                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10584                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10585                new_selections.push(open_offset..open_offset);
10586                new_selections.push(close_offset..close_offset);
10587            }
10588
10589            this.change_selections(Default::default(), window, cx, |s| {
10590                s.select_ranges(new_selections);
10591            });
10592
10593            this.request_autoscroll(Autoscroll::fit(), cx);
10594        });
10595    }
10596
10597    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10598        let Some(project) = self.project.clone() else {
10599            return;
10600        };
10601        self.reload(project, window, cx)
10602            .detach_and_notify_err(window, cx);
10603    }
10604
10605    pub fn restore_file(
10606        &mut self,
10607        _: &::git::RestoreFile,
10608        window: &mut Window,
10609        cx: &mut Context<Self>,
10610    ) {
10611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612        let mut buffer_ids = HashSet::default();
10613        let snapshot = self.buffer().read(cx).snapshot(cx);
10614        for selection in self.selections.all::<usize>(cx) {
10615            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10616        }
10617
10618        let buffer = self.buffer().read(cx);
10619        let ranges = buffer_ids
10620            .into_iter()
10621            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10622            .collect::<Vec<_>>();
10623
10624        self.restore_hunks_in_ranges(ranges, window, cx);
10625    }
10626
10627    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10629        let selections = self
10630            .selections
10631            .all(cx)
10632            .into_iter()
10633            .map(|s| s.range())
10634            .collect();
10635        self.restore_hunks_in_ranges(selections, window, cx);
10636    }
10637
10638    pub fn restore_hunks_in_ranges(
10639        &mut self,
10640        ranges: Vec<Range<Point>>,
10641        window: &mut Window,
10642        cx: &mut Context<Editor>,
10643    ) {
10644        let mut revert_changes = HashMap::default();
10645        let chunk_by = self
10646            .snapshot(window, cx)
10647            .hunks_for_ranges(ranges)
10648            .into_iter()
10649            .chunk_by(|hunk| hunk.buffer_id);
10650        for (buffer_id, hunks) in &chunk_by {
10651            let hunks = hunks.collect::<Vec<_>>();
10652            for hunk in &hunks {
10653                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10654            }
10655            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10656        }
10657        drop(chunk_by);
10658        if !revert_changes.is_empty() {
10659            self.transact(window, cx, |editor, window, cx| {
10660                editor.restore(revert_changes, window, cx);
10661            });
10662        }
10663    }
10664
10665    pub fn open_active_item_in_terminal(
10666        &mut self,
10667        _: &OpenInTerminal,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10672            let project_path = buffer.read(cx).project_path(cx)?;
10673            let project = self.project()?.read(cx);
10674            let entry = project.entry_for_path(&project_path, cx)?;
10675            let parent = match &entry.canonical_path {
10676                Some(canonical_path) => canonical_path.to_path_buf(),
10677                None => project.absolute_path(&project_path, cx)?,
10678            }
10679            .parent()?
10680            .to_path_buf();
10681            Some(parent)
10682        }) {
10683            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10684        }
10685    }
10686
10687    fn set_breakpoint_context_menu(
10688        &mut self,
10689        display_row: DisplayRow,
10690        position: Option<Anchor>,
10691        clicked_point: gpui::Point<Pixels>,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        let source = self
10696            .buffer
10697            .read(cx)
10698            .snapshot(cx)
10699            .anchor_before(Point::new(display_row.0, 0u32));
10700
10701        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10702
10703        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10704            self,
10705            source,
10706            clicked_point,
10707            context_menu,
10708            window,
10709            cx,
10710        );
10711    }
10712
10713    fn add_edit_breakpoint_block(
10714        &mut self,
10715        anchor: Anchor,
10716        breakpoint: &Breakpoint,
10717        edit_action: BreakpointPromptEditAction,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        let weak_editor = cx.weak_entity();
10722        let bp_prompt = cx.new(|cx| {
10723            BreakpointPromptEditor::new(
10724                weak_editor,
10725                anchor,
10726                breakpoint.clone(),
10727                edit_action,
10728                window,
10729                cx,
10730            )
10731        });
10732
10733        let height = bp_prompt.update(cx, |this, cx| {
10734            this.prompt
10735                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10736        });
10737        let cloned_prompt = bp_prompt.clone();
10738        let blocks = vec![BlockProperties {
10739            style: BlockStyle::Sticky,
10740            placement: BlockPlacement::Above(anchor),
10741            height: Some(height),
10742            render: Arc::new(move |cx| {
10743                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10744                cloned_prompt.clone().into_any_element()
10745            }),
10746            priority: 0,
10747        }];
10748
10749        let focus_handle = bp_prompt.focus_handle(cx);
10750        window.focus(&focus_handle);
10751
10752        let block_ids = self.insert_blocks(blocks, None, cx);
10753        bp_prompt.update(cx, |prompt, _| {
10754            prompt.add_block_ids(block_ids);
10755        });
10756    }
10757
10758    pub(crate) fn breakpoint_at_row(
10759        &self,
10760        row: u32,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) -> Option<(Anchor, Breakpoint)> {
10764        let snapshot = self.snapshot(window, cx);
10765        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10766
10767        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10768    }
10769
10770    pub(crate) fn breakpoint_at_anchor(
10771        &self,
10772        breakpoint_position: Anchor,
10773        snapshot: &EditorSnapshot,
10774        cx: &mut Context<Self>,
10775    ) -> Option<(Anchor, Breakpoint)> {
10776        let buffer = self
10777            .buffer
10778            .read(cx)
10779            .buffer_for_anchor(breakpoint_position, cx)?;
10780
10781        let enclosing_excerpt = breakpoint_position.excerpt_id;
10782        let buffer_snapshot = buffer.read(cx).snapshot();
10783
10784        let row = buffer_snapshot
10785            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10786            .row;
10787
10788        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10789        let anchor_end = snapshot
10790            .buffer_snapshot
10791            .anchor_after(Point::new(row, line_len));
10792
10793        self.breakpoint_store
10794            .as_ref()?
10795            .read_with(cx, |breakpoint_store, cx| {
10796                breakpoint_store
10797                    .breakpoints(
10798                        &buffer,
10799                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10800                        &buffer_snapshot,
10801                        cx,
10802                    )
10803                    .next()
10804                    .and_then(|(bp, _)| {
10805                        let breakpoint_row = buffer_snapshot
10806                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10807                            .row;
10808
10809                        if breakpoint_row == row {
10810                            snapshot
10811                                .buffer_snapshot
10812                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10813                                .map(|position| (position, bp.bp.clone()))
10814                        } else {
10815                            None
10816                        }
10817                    })
10818            })
10819    }
10820
10821    pub fn edit_log_breakpoint(
10822        &mut self,
10823        _: &EditLogBreakpoint,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10828            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10829                message: None,
10830                state: BreakpointState::Enabled,
10831                condition: None,
10832                hit_condition: None,
10833            });
10834
10835            self.add_edit_breakpoint_block(
10836                anchor,
10837                &breakpoint,
10838                BreakpointPromptEditAction::Log,
10839                window,
10840                cx,
10841            );
10842        }
10843    }
10844
10845    fn breakpoints_at_cursors(
10846        &self,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10850        let snapshot = self.snapshot(window, cx);
10851        let cursors = self
10852            .selections
10853            .disjoint_anchors_arc()
10854            .iter()
10855            .map(|selection| {
10856                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10857
10858                let breakpoint_position = self
10859                    .breakpoint_at_row(cursor_position.row, window, cx)
10860                    .map(|bp| bp.0)
10861                    .unwrap_or_else(|| {
10862                        snapshot
10863                            .display_snapshot
10864                            .buffer_snapshot
10865                            .anchor_after(Point::new(cursor_position.row, 0))
10866                    });
10867
10868                let breakpoint = self
10869                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10870                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10871
10872                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10873            })
10874            // 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.
10875            .collect::<HashMap<Anchor, _>>();
10876
10877        cursors.into_iter().collect()
10878    }
10879
10880    pub fn enable_breakpoint(
10881        &mut self,
10882        _: &crate::actions::EnableBreakpoint,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10887            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10888                continue;
10889            };
10890            self.edit_breakpoint_at_anchor(
10891                anchor,
10892                breakpoint,
10893                BreakpointEditAction::InvertState,
10894                cx,
10895            );
10896        }
10897    }
10898
10899    pub fn disable_breakpoint(
10900        &mut self,
10901        _: &crate::actions::DisableBreakpoint,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10906            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10907                continue;
10908            };
10909            self.edit_breakpoint_at_anchor(
10910                anchor,
10911                breakpoint,
10912                BreakpointEditAction::InvertState,
10913                cx,
10914            );
10915        }
10916    }
10917
10918    pub fn toggle_breakpoint(
10919        &mut self,
10920        _: &crate::actions::ToggleBreakpoint,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10925            if let Some(breakpoint) = breakpoint {
10926                self.edit_breakpoint_at_anchor(
10927                    anchor,
10928                    breakpoint,
10929                    BreakpointEditAction::Toggle,
10930                    cx,
10931                );
10932            } else {
10933                self.edit_breakpoint_at_anchor(
10934                    anchor,
10935                    Breakpoint::new_standard(),
10936                    BreakpointEditAction::Toggle,
10937                    cx,
10938                );
10939            }
10940        }
10941    }
10942
10943    pub fn edit_breakpoint_at_anchor(
10944        &mut self,
10945        breakpoint_position: Anchor,
10946        breakpoint: Breakpoint,
10947        edit_action: BreakpointEditAction,
10948        cx: &mut Context<Self>,
10949    ) {
10950        let Some(breakpoint_store) = &self.breakpoint_store else {
10951            return;
10952        };
10953
10954        let Some(buffer) = self
10955            .buffer
10956            .read(cx)
10957            .buffer_for_anchor(breakpoint_position, cx)
10958        else {
10959            return;
10960        };
10961
10962        breakpoint_store.update(cx, |breakpoint_store, cx| {
10963            breakpoint_store.toggle_breakpoint(
10964                buffer,
10965                BreakpointWithPosition {
10966                    position: breakpoint_position.text_anchor,
10967                    bp: breakpoint,
10968                },
10969                edit_action,
10970                cx,
10971            );
10972        });
10973
10974        cx.notify();
10975    }
10976
10977    #[cfg(any(test, feature = "test-support"))]
10978    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10979        self.breakpoint_store.clone()
10980    }
10981
10982    pub fn prepare_restore_change(
10983        &self,
10984        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10985        hunk: &MultiBufferDiffHunk,
10986        cx: &mut App,
10987    ) -> Option<()> {
10988        if hunk.is_created_file() {
10989            return None;
10990        }
10991        let buffer = self.buffer.read(cx);
10992        let diff = buffer.diff_for(hunk.buffer_id)?;
10993        let buffer = buffer.buffer(hunk.buffer_id)?;
10994        let buffer = buffer.read(cx);
10995        let original_text = diff
10996            .read(cx)
10997            .base_text()
10998            .as_rope()
10999            .slice(hunk.diff_base_byte_range.clone());
11000        let buffer_snapshot = buffer.snapshot();
11001        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11002        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11003            probe
11004                .0
11005                .start
11006                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11007                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11008        }) {
11009            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11010            Some(())
11011        } else {
11012            None
11013        }
11014    }
11015
11016    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11017        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11018    }
11019
11020    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11021        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11022    }
11023
11024    fn manipulate_lines<M>(
11025        &mut self,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028        mut manipulate: M,
11029    ) where
11030        M: FnMut(&str) -> LineManipulationResult,
11031    {
11032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11033
11034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11035        let buffer = self.buffer.read(cx).snapshot(cx);
11036
11037        let mut edits = Vec::new();
11038
11039        let selections = self.selections.all::<Point>(cx);
11040        let mut selections = selections.iter().peekable();
11041        let mut contiguous_row_selections = Vec::new();
11042        let mut new_selections = Vec::new();
11043        let mut added_lines = 0;
11044        let mut removed_lines = 0;
11045
11046        while let Some(selection) = selections.next() {
11047            let (start_row, end_row) = consume_contiguous_rows(
11048                &mut contiguous_row_selections,
11049                selection,
11050                &display_map,
11051                &mut selections,
11052            );
11053
11054            let start_point = Point::new(start_row.0, 0);
11055            let end_point = Point::new(
11056                end_row.previous_row().0,
11057                buffer.line_len(end_row.previous_row()),
11058            );
11059            let text = buffer
11060                .text_for_range(start_point..end_point)
11061                .collect::<String>();
11062
11063            let LineManipulationResult {
11064                new_text,
11065                line_count_before,
11066                line_count_after,
11067            } = manipulate(&text);
11068
11069            edits.push((start_point..end_point, new_text));
11070
11071            // Selections must change based on added and removed line count
11072            let start_row =
11073                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11074            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11075            new_selections.push(Selection {
11076                id: selection.id,
11077                start: start_row,
11078                end: end_row,
11079                goal: SelectionGoal::None,
11080                reversed: selection.reversed,
11081            });
11082
11083            if line_count_after > line_count_before {
11084                added_lines += line_count_after - line_count_before;
11085            } else if line_count_before > line_count_after {
11086                removed_lines += line_count_before - line_count_after;
11087            }
11088        }
11089
11090        self.transact(window, cx, |this, window, cx| {
11091            let buffer = this.buffer.update(cx, |buffer, cx| {
11092                buffer.edit(edits, None, cx);
11093                buffer.snapshot(cx)
11094            });
11095
11096            // Recalculate offsets on newly edited buffer
11097            let new_selections = new_selections
11098                .iter()
11099                .map(|s| {
11100                    let start_point = Point::new(s.start.0, 0);
11101                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11102                    Selection {
11103                        id: s.id,
11104                        start: buffer.point_to_offset(start_point),
11105                        end: buffer.point_to_offset(end_point),
11106                        goal: s.goal,
11107                        reversed: s.reversed,
11108                    }
11109                })
11110                .collect();
11111
11112            this.change_selections(Default::default(), window, cx, |s| {
11113                s.select(new_selections);
11114            });
11115
11116            this.request_autoscroll(Autoscroll::fit(), cx);
11117        });
11118    }
11119
11120    fn manipulate_immutable_lines<Fn>(
11121        &mut self,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124        mut callback: Fn,
11125    ) where
11126        Fn: FnMut(&mut Vec<&str>),
11127    {
11128        self.manipulate_lines(window, cx, |text| {
11129            let mut lines: Vec<&str> = text.split('\n').collect();
11130            let line_count_before = lines.len();
11131
11132            callback(&mut lines);
11133
11134            LineManipulationResult {
11135                new_text: lines.join("\n"),
11136                line_count_before,
11137                line_count_after: lines.len(),
11138            }
11139        });
11140    }
11141
11142    fn manipulate_mutable_lines<Fn>(
11143        &mut self,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146        mut callback: Fn,
11147    ) where
11148        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11149    {
11150        self.manipulate_lines(window, cx, |text| {
11151            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11152            let line_count_before = lines.len();
11153
11154            callback(&mut lines);
11155
11156            LineManipulationResult {
11157                new_text: lines.join("\n"),
11158                line_count_before,
11159                line_count_after: lines.len(),
11160            }
11161        });
11162    }
11163
11164    pub fn convert_indentation_to_spaces(
11165        &mut self,
11166        _: &ConvertIndentationToSpaces,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        let settings = self.buffer.read(cx).language_settings(cx);
11171        let tab_size = settings.tab_size.get() as usize;
11172
11173        self.manipulate_mutable_lines(window, cx, |lines| {
11174            // Allocates a reasonably sized scratch buffer once for the whole loop
11175            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11176            // Avoids recomputing spaces that could be inserted many times
11177            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11178                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11179                .collect();
11180
11181            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11182                let mut chars = line.as_ref().chars();
11183                let mut col = 0;
11184                let mut changed = false;
11185
11186                for ch in chars.by_ref() {
11187                    match ch {
11188                        ' ' => {
11189                            reindented_line.push(' ');
11190                            col += 1;
11191                        }
11192                        '\t' => {
11193                            // \t are converted to spaces depending on the current column
11194                            let spaces_len = tab_size - (col % tab_size);
11195                            reindented_line.extend(&space_cache[spaces_len - 1]);
11196                            col += spaces_len;
11197                            changed = true;
11198                        }
11199                        _ => {
11200                            // If we dont append before break, the character is consumed
11201                            reindented_line.push(ch);
11202                            break;
11203                        }
11204                    }
11205                }
11206
11207                if !changed {
11208                    reindented_line.clear();
11209                    continue;
11210                }
11211                // Append the rest of the line and replace old reference with new one
11212                reindented_line.extend(chars);
11213                *line = Cow::Owned(reindented_line.clone());
11214                reindented_line.clear();
11215            }
11216        });
11217    }
11218
11219    pub fn convert_indentation_to_tabs(
11220        &mut self,
11221        _: &ConvertIndentationToTabs,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        let settings = self.buffer.read(cx).language_settings(cx);
11226        let tab_size = settings.tab_size.get() as usize;
11227
11228        self.manipulate_mutable_lines(window, cx, |lines| {
11229            // Allocates a reasonably sized buffer once for the whole loop
11230            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11231            // Avoids recomputing spaces that could be inserted many times
11232            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11233                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11234                .collect();
11235
11236            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11237                let mut chars = line.chars();
11238                let mut spaces_count = 0;
11239                let mut first_non_indent_char = None;
11240                let mut changed = false;
11241
11242                for ch in chars.by_ref() {
11243                    match ch {
11244                        ' ' => {
11245                            // Keep track of spaces. Append \t when we reach tab_size
11246                            spaces_count += 1;
11247                            changed = true;
11248                            if spaces_count == tab_size {
11249                                reindented_line.push('\t');
11250                                spaces_count = 0;
11251                            }
11252                        }
11253                        '\t' => {
11254                            reindented_line.push('\t');
11255                            spaces_count = 0;
11256                        }
11257                        _ => {
11258                            // Dont append it yet, we might have remaining spaces
11259                            first_non_indent_char = Some(ch);
11260                            break;
11261                        }
11262                    }
11263                }
11264
11265                if !changed {
11266                    reindented_line.clear();
11267                    continue;
11268                }
11269                // Remaining spaces that didn't make a full tab stop
11270                if spaces_count > 0 {
11271                    reindented_line.extend(&space_cache[spaces_count - 1]);
11272                }
11273                // If we consume an extra character that was not indentation, add it back
11274                if let Some(extra_char) = first_non_indent_char {
11275                    reindented_line.push(extra_char);
11276                }
11277                // Append the rest of the line and replace old reference with new one
11278                reindented_line.extend(chars);
11279                *line = Cow::Owned(reindented_line.clone());
11280                reindented_line.clear();
11281            }
11282        });
11283    }
11284
11285    pub fn convert_to_upper_case(
11286        &mut self,
11287        _: &ConvertToUpperCase,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        self.manipulate_text(window, cx, |text| text.to_uppercase())
11292    }
11293
11294    pub fn convert_to_lower_case(
11295        &mut self,
11296        _: &ConvertToLowerCase,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.manipulate_text(window, cx, |text| text.to_lowercase())
11301    }
11302
11303    pub fn convert_to_title_case(
11304        &mut self,
11305        _: &ConvertToTitleCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.split('\n')
11311                .map(|line| line.to_case(Case::Title))
11312                .join("\n")
11313        })
11314    }
11315
11316    pub fn convert_to_snake_case(
11317        &mut self,
11318        _: &ConvertToSnakeCase,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11323    }
11324
11325    pub fn convert_to_kebab_case(
11326        &mut self,
11327        _: &ConvertToKebabCase,
11328        window: &mut Window,
11329        cx: &mut Context<Self>,
11330    ) {
11331        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11332    }
11333
11334    pub fn convert_to_upper_camel_case(
11335        &mut self,
11336        _: &ConvertToUpperCamelCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| {
11341            text.split('\n')
11342                .map(|line| line.to_case(Case::UpperCamel))
11343                .join("\n")
11344        })
11345    }
11346
11347    pub fn convert_to_lower_camel_case(
11348        &mut self,
11349        _: &ConvertToLowerCamelCase,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11354    }
11355
11356    pub fn convert_to_opposite_case(
11357        &mut self,
11358        _: &ConvertToOppositeCase,
11359        window: &mut Window,
11360        cx: &mut Context<Self>,
11361    ) {
11362        self.manipulate_text(window, cx, |text| {
11363            text.chars()
11364                .fold(String::with_capacity(text.len()), |mut t, c| {
11365                    if c.is_uppercase() {
11366                        t.extend(c.to_lowercase());
11367                    } else {
11368                        t.extend(c.to_uppercase());
11369                    }
11370                    t
11371                })
11372        })
11373    }
11374
11375    pub fn convert_to_sentence_case(
11376        &mut self,
11377        _: &ConvertToSentenceCase,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11382    }
11383
11384    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11385        self.manipulate_text(window, cx, |text| {
11386            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11387            if has_upper_case_characters {
11388                text.to_lowercase()
11389            } else {
11390                text.to_uppercase()
11391            }
11392        })
11393    }
11394
11395    pub fn convert_to_rot13(
11396        &mut self,
11397        _: &ConvertToRot13,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        self.manipulate_text(window, cx, |text| {
11402            text.chars()
11403                .map(|c| match c {
11404                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11405                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11406                    _ => c,
11407                })
11408                .collect()
11409        })
11410    }
11411
11412    pub fn convert_to_rot47(
11413        &mut self,
11414        _: &ConvertToRot47,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.manipulate_text(window, cx, |text| {
11419            text.chars()
11420                .map(|c| {
11421                    let code_point = c as u32;
11422                    if code_point >= 33 && code_point <= 126 {
11423                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11424                    }
11425                    c
11426                })
11427                .collect()
11428        })
11429    }
11430
11431    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11432    where
11433        Fn: FnMut(&str) -> String,
11434    {
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436
11437        let mut new_selections = Vec::new();
11438        let mut edits = Vec::new();
11439        let mut selection_adjustment = 0i32;
11440
11441        for selection in self.selections.all_adjusted(cx) {
11442            let selection_is_empty = selection.is_empty();
11443
11444            let (start, end) = if selection_is_empty {
11445                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11446                (word_range.start, word_range.end)
11447            } else {
11448                (
11449                    buffer.point_to_offset(selection.start),
11450                    buffer.point_to_offset(selection.end),
11451                )
11452            };
11453
11454            let text = buffer.text_for_range(start..end).collect::<String>();
11455            let old_length = text.len() as i32;
11456            let text = callback(&text);
11457
11458            new_selections.push(Selection {
11459                start: (start as i32 - selection_adjustment) as usize,
11460                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11461                goal: SelectionGoal::None,
11462                id: selection.id,
11463                reversed: selection.reversed,
11464            });
11465
11466            selection_adjustment += old_length - text.len() as i32;
11467
11468            edits.push((start..end, text));
11469        }
11470
11471        self.transact(window, cx, |this, window, cx| {
11472            this.buffer.update(cx, |buffer, cx| {
11473                buffer.edit(edits, None, cx);
11474            });
11475
11476            this.change_selections(Default::default(), window, cx, |s| {
11477                s.select(new_selections);
11478            });
11479
11480            this.request_autoscroll(Autoscroll::fit(), cx);
11481        });
11482    }
11483
11484    pub fn move_selection_on_drop(
11485        &mut self,
11486        selection: &Selection<Anchor>,
11487        target: DisplayPoint,
11488        is_cut: bool,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11493        let buffer = &display_map.buffer_snapshot;
11494        let mut edits = Vec::new();
11495        let insert_point = display_map
11496            .clip_point(target, Bias::Left)
11497            .to_point(&display_map);
11498        let text = buffer
11499            .text_for_range(selection.start..selection.end)
11500            .collect::<String>();
11501        if is_cut {
11502            edits.push(((selection.start..selection.end), String::new()));
11503        }
11504        let insert_anchor = buffer.anchor_before(insert_point);
11505        edits.push(((insert_anchor..insert_anchor), text));
11506        let last_edit_start = insert_anchor.bias_left(buffer);
11507        let last_edit_end = insert_anchor.bias_right(buffer);
11508        self.transact(window, cx, |this, window, cx| {
11509            this.buffer.update(cx, |buffer, cx| {
11510                buffer.edit(edits, None, cx);
11511            });
11512            this.change_selections(Default::default(), window, cx, |s| {
11513                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11514            });
11515        });
11516    }
11517
11518    pub fn clear_selection_drag_state(&mut self) {
11519        self.selection_drag_state = SelectionDragState::None;
11520    }
11521
11522    pub fn duplicate(
11523        &mut self,
11524        upwards: bool,
11525        whole_lines: bool,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11530
11531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11532        let buffer = &display_map.buffer_snapshot;
11533        let selections = self.selections.all::<Point>(cx);
11534
11535        let mut edits = Vec::new();
11536        let mut selections_iter = selections.iter().peekable();
11537        while let Some(selection) = selections_iter.next() {
11538            let mut rows = selection.spanned_rows(false, &display_map);
11539            // duplicate line-wise
11540            if whole_lines || selection.start == selection.end {
11541                // Avoid duplicating the same lines twice.
11542                while let Some(next_selection) = selections_iter.peek() {
11543                    let next_rows = next_selection.spanned_rows(false, &display_map);
11544                    if next_rows.start < rows.end {
11545                        rows.end = next_rows.end;
11546                        selections_iter.next().unwrap();
11547                    } else {
11548                        break;
11549                    }
11550                }
11551
11552                // Copy the text from the selected row region and splice it either at the start
11553                // or end of the region.
11554                let start = Point::new(rows.start.0, 0);
11555                let end = Point::new(
11556                    rows.end.previous_row().0,
11557                    buffer.line_len(rows.end.previous_row()),
11558                );
11559                let text = buffer
11560                    .text_for_range(start..end)
11561                    .chain(Some("\n"))
11562                    .collect::<String>();
11563                let insert_location = if upwards {
11564                    Point::new(rows.end.0, 0)
11565                } else {
11566                    start
11567                };
11568                edits.push((insert_location..insert_location, text));
11569            } else {
11570                // duplicate character-wise
11571                let start = selection.start;
11572                let end = selection.end;
11573                let text = buffer.text_for_range(start..end).collect::<String>();
11574                edits.push((selection.end..selection.end, text));
11575            }
11576        }
11577
11578        self.transact(window, cx, |this, _, cx| {
11579            this.buffer.update(cx, |buffer, cx| {
11580                buffer.edit(edits, None, cx);
11581            });
11582
11583            this.request_autoscroll(Autoscroll::fit(), cx);
11584        });
11585    }
11586
11587    pub fn duplicate_line_up(
11588        &mut self,
11589        _: &DuplicateLineUp,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.duplicate(true, true, window, cx);
11594    }
11595
11596    pub fn duplicate_line_down(
11597        &mut self,
11598        _: &DuplicateLineDown,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.duplicate(false, true, window, cx);
11603    }
11604
11605    pub fn duplicate_selection(
11606        &mut self,
11607        _: &DuplicateSelection,
11608        window: &mut Window,
11609        cx: &mut Context<Self>,
11610    ) {
11611        self.duplicate(false, false, window, cx);
11612    }
11613
11614    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11616        if self.mode.is_single_line() {
11617            cx.propagate();
11618            return;
11619        }
11620
11621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11622        let buffer = self.buffer.read(cx).snapshot(cx);
11623
11624        let mut edits = Vec::new();
11625        let mut unfold_ranges = Vec::new();
11626        let mut refold_creases = Vec::new();
11627
11628        let selections = self.selections.all::<Point>(cx);
11629        let mut selections = selections.iter().peekable();
11630        let mut contiguous_row_selections = Vec::new();
11631        let mut new_selections = Vec::new();
11632
11633        while let Some(selection) = selections.next() {
11634            // Find all the selections that span a contiguous row range
11635            let (start_row, end_row) = consume_contiguous_rows(
11636                &mut contiguous_row_selections,
11637                selection,
11638                &display_map,
11639                &mut selections,
11640            );
11641
11642            // Move the text spanned by the row range to be before the line preceding the row range
11643            if start_row.0 > 0 {
11644                let range_to_move = Point::new(
11645                    start_row.previous_row().0,
11646                    buffer.line_len(start_row.previous_row()),
11647                )
11648                    ..Point::new(
11649                        end_row.previous_row().0,
11650                        buffer.line_len(end_row.previous_row()),
11651                    );
11652                let insertion_point = display_map
11653                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11654                    .0;
11655
11656                // Don't move lines across excerpts
11657                if buffer
11658                    .excerpt_containing(insertion_point..range_to_move.end)
11659                    .is_some()
11660                {
11661                    let text = buffer
11662                        .text_for_range(range_to_move.clone())
11663                        .flat_map(|s| s.chars())
11664                        .skip(1)
11665                        .chain(['\n'])
11666                        .collect::<String>();
11667
11668                    edits.push((
11669                        buffer.anchor_after(range_to_move.start)
11670                            ..buffer.anchor_before(range_to_move.end),
11671                        String::new(),
11672                    ));
11673                    let insertion_anchor = buffer.anchor_after(insertion_point);
11674                    edits.push((insertion_anchor..insertion_anchor, text));
11675
11676                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11677
11678                    // Move selections up
11679                    new_selections.extend(contiguous_row_selections.drain(..).map(
11680                        |mut selection| {
11681                            selection.start.row -= row_delta;
11682                            selection.end.row -= row_delta;
11683                            selection
11684                        },
11685                    ));
11686
11687                    // Move folds up
11688                    unfold_ranges.push(range_to_move.clone());
11689                    for fold in display_map.folds_in_range(
11690                        buffer.anchor_before(range_to_move.start)
11691                            ..buffer.anchor_after(range_to_move.end),
11692                    ) {
11693                        let mut start = fold.range.start.to_point(&buffer);
11694                        let mut end = fold.range.end.to_point(&buffer);
11695                        start.row -= row_delta;
11696                        end.row -= row_delta;
11697                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11698                    }
11699                }
11700            }
11701
11702            // If we didn't move line(s), preserve the existing selections
11703            new_selections.append(&mut contiguous_row_selections);
11704        }
11705
11706        self.transact(window, cx, |this, window, cx| {
11707            this.unfold_ranges(&unfold_ranges, true, true, cx);
11708            this.buffer.update(cx, |buffer, cx| {
11709                for (range, text) in edits {
11710                    buffer.edit([(range, text)], None, cx);
11711                }
11712            });
11713            this.fold_creases(refold_creases, true, window, cx);
11714            this.change_selections(Default::default(), window, cx, |s| {
11715                s.select(new_selections);
11716            })
11717        });
11718    }
11719
11720    pub fn move_line_down(
11721        &mut self,
11722        _: &MoveLineDown,
11723        window: &mut Window,
11724        cx: &mut Context<Self>,
11725    ) {
11726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11727        if self.mode.is_single_line() {
11728            cx.propagate();
11729            return;
11730        }
11731
11732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11733        let buffer = self.buffer.read(cx).snapshot(cx);
11734
11735        let mut edits = Vec::new();
11736        let mut unfold_ranges = Vec::new();
11737        let mut refold_creases = Vec::new();
11738
11739        let selections = self.selections.all::<Point>(cx);
11740        let mut selections = selections.iter().peekable();
11741        let mut contiguous_row_selections = Vec::new();
11742        let mut new_selections = Vec::new();
11743
11744        while let Some(selection) = selections.next() {
11745            // Find all the selections that span a contiguous row range
11746            let (start_row, end_row) = consume_contiguous_rows(
11747                &mut contiguous_row_selections,
11748                selection,
11749                &display_map,
11750                &mut selections,
11751            );
11752
11753            // Move the text spanned by the row range to be after the last line of the row range
11754            if end_row.0 <= buffer.max_point().row {
11755                let range_to_move =
11756                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11757                let insertion_point = display_map
11758                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11759                    .0;
11760
11761                // Don't move lines across excerpt boundaries
11762                if buffer
11763                    .excerpt_containing(range_to_move.start..insertion_point)
11764                    .is_some()
11765                {
11766                    let mut text = String::from("\n");
11767                    text.extend(buffer.text_for_range(range_to_move.clone()));
11768                    text.pop(); // Drop trailing newline
11769                    edits.push((
11770                        buffer.anchor_after(range_to_move.start)
11771                            ..buffer.anchor_before(range_to_move.end),
11772                        String::new(),
11773                    ));
11774                    let insertion_anchor = buffer.anchor_after(insertion_point);
11775                    edits.push((insertion_anchor..insertion_anchor, text));
11776
11777                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11778
11779                    // Move selections down
11780                    new_selections.extend(contiguous_row_selections.drain(..).map(
11781                        |mut selection| {
11782                            selection.start.row += row_delta;
11783                            selection.end.row += row_delta;
11784                            selection
11785                        },
11786                    ));
11787
11788                    // Move folds down
11789                    unfold_ranges.push(range_to_move.clone());
11790                    for fold in display_map.folds_in_range(
11791                        buffer.anchor_before(range_to_move.start)
11792                            ..buffer.anchor_after(range_to_move.end),
11793                    ) {
11794                        let mut start = fold.range.start.to_point(&buffer);
11795                        let mut end = fold.range.end.to_point(&buffer);
11796                        start.row += row_delta;
11797                        end.row += row_delta;
11798                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11799                    }
11800                }
11801            }
11802
11803            // If we didn't move line(s), preserve the existing selections
11804            new_selections.append(&mut contiguous_row_selections);
11805        }
11806
11807        self.transact(window, cx, |this, window, cx| {
11808            this.unfold_ranges(&unfold_ranges, true, true, cx);
11809            this.buffer.update(cx, |buffer, cx| {
11810                for (range, text) in edits {
11811                    buffer.edit([(range, text)], None, cx);
11812                }
11813            });
11814            this.fold_creases(refold_creases, true, window, cx);
11815            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11816        });
11817    }
11818
11819    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11821        let text_layout_details = &self.text_layout_details(window);
11822        self.transact(window, cx, |this, window, cx| {
11823            let edits = this.change_selections(Default::default(), window, cx, |s| {
11824                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11825                s.move_with(|display_map, selection| {
11826                    if !selection.is_empty() {
11827                        return;
11828                    }
11829
11830                    let mut head = selection.head();
11831                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11832                    if head.column() == display_map.line_len(head.row()) {
11833                        transpose_offset = display_map
11834                            .buffer_snapshot
11835                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11836                    }
11837
11838                    if transpose_offset == 0 {
11839                        return;
11840                    }
11841
11842                    *head.column_mut() += 1;
11843                    head = display_map.clip_point(head, Bias::Right);
11844                    let goal = SelectionGoal::HorizontalPosition(
11845                        display_map
11846                            .x_for_display_point(head, text_layout_details)
11847                            .into(),
11848                    );
11849                    selection.collapse_to(head, goal);
11850
11851                    let transpose_start = display_map
11852                        .buffer_snapshot
11853                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11854                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11855                        let transpose_end = display_map
11856                            .buffer_snapshot
11857                            .clip_offset(transpose_offset + 1, Bias::Right);
11858                        if let Some(ch) =
11859                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11860                        {
11861                            edits.push((transpose_start..transpose_offset, String::new()));
11862                            edits.push((transpose_end..transpose_end, ch.to_string()));
11863                        }
11864                    }
11865                });
11866                edits
11867            });
11868            this.buffer
11869                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11870            let selections = this.selections.all::<usize>(cx);
11871            this.change_selections(Default::default(), window, cx, |s| {
11872                s.select(selections);
11873            });
11874        });
11875    }
11876
11877    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11879        if self.mode.is_single_line() {
11880            cx.propagate();
11881            return;
11882        }
11883
11884        self.rewrap_impl(RewrapOptions::default(), cx)
11885    }
11886
11887    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11888        let buffer = self.buffer.read(cx).snapshot(cx);
11889        let selections = self.selections.all::<Point>(cx);
11890
11891        #[derive(Clone, Debug, PartialEq)]
11892        enum CommentFormat {
11893            /// single line comment, with prefix for line
11894            Line(String),
11895            /// single line within a block comment, with prefix for line
11896            BlockLine(String),
11897            /// a single line of a block comment that includes the initial delimiter
11898            BlockCommentWithStart(BlockCommentConfig),
11899            /// a single line of a block comment that includes the ending delimiter
11900            BlockCommentWithEnd(BlockCommentConfig),
11901        }
11902
11903        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11904        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11905            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11906                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11907                .peekable();
11908
11909            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11910                row
11911            } else {
11912                return Vec::new();
11913            };
11914
11915            let language_settings = buffer.language_settings_at(selection.head(), cx);
11916            let language_scope = buffer.language_scope_at(selection.head());
11917
11918            let indent_and_prefix_for_row =
11919                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11920                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11921                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11922                        &language_scope
11923                    {
11924                        let indent_end = Point::new(row, indent.len);
11925                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11926                        let line_text_after_indent = buffer
11927                            .text_for_range(indent_end..line_end)
11928                            .collect::<String>();
11929
11930                        let is_within_comment_override = buffer
11931                            .language_scope_at(indent_end)
11932                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11933                        let comment_delimiters = if is_within_comment_override {
11934                            // we are within a comment syntax node, but we don't
11935                            // yet know what kind of comment: block, doc or line
11936                            match (
11937                                language_scope.documentation_comment(),
11938                                language_scope.block_comment(),
11939                            ) {
11940                                (Some(config), _) | (_, Some(config))
11941                                    if buffer.contains_str_at(indent_end, &config.start) =>
11942                                {
11943                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11944                                }
11945                                (Some(config), _) | (_, Some(config))
11946                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11947                                {
11948                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11949                                }
11950                                (Some(config), _) | (_, Some(config))
11951                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11952                                {
11953                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11954                                }
11955                                (_, _) => language_scope
11956                                    .line_comment_prefixes()
11957                                    .iter()
11958                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11959                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11960                            }
11961                        } else {
11962                            // we not in an overridden comment node, but we may
11963                            // be within a non-overridden line comment node
11964                            language_scope
11965                                .line_comment_prefixes()
11966                                .iter()
11967                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11968                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11969                        };
11970
11971                        let rewrap_prefix = language_scope
11972                            .rewrap_prefixes()
11973                            .iter()
11974                            .find_map(|prefix_regex| {
11975                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11976                                    if mat.start() == 0 {
11977                                        Some(mat.as_str().to_string())
11978                                    } else {
11979                                        None
11980                                    }
11981                                })
11982                            })
11983                            .flatten();
11984                        (comment_delimiters, rewrap_prefix)
11985                    } else {
11986                        (None, None)
11987                    };
11988                    (indent, comment_prefix, rewrap_prefix)
11989                };
11990
11991            let mut ranges = Vec::new();
11992            let from_empty_selection = selection.is_empty();
11993
11994            let mut current_range_start = first_row;
11995            let mut prev_row = first_row;
11996            let (
11997                mut current_range_indent,
11998                mut current_range_comment_delimiters,
11999                mut current_range_rewrap_prefix,
12000            ) = indent_and_prefix_for_row(first_row);
12001
12002            for row in non_blank_rows_iter.skip(1) {
12003                let has_paragraph_break = row > prev_row + 1;
12004
12005                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12006                    indent_and_prefix_for_row(row);
12007
12008                let has_indent_change = row_indent != current_range_indent;
12009                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12010
12011                let has_boundary_change = has_comment_change
12012                    || row_rewrap_prefix.is_some()
12013                    || (has_indent_change && current_range_comment_delimiters.is_some());
12014
12015                if has_paragraph_break || has_boundary_change {
12016                    ranges.push((
12017                        language_settings.clone(),
12018                        Point::new(current_range_start, 0)
12019                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12020                        current_range_indent,
12021                        current_range_comment_delimiters.clone(),
12022                        current_range_rewrap_prefix.clone(),
12023                        from_empty_selection,
12024                    ));
12025                    current_range_start = row;
12026                    current_range_indent = row_indent;
12027                    current_range_comment_delimiters = row_comment_delimiters;
12028                    current_range_rewrap_prefix = row_rewrap_prefix;
12029                }
12030                prev_row = row;
12031            }
12032
12033            ranges.push((
12034                language_settings.clone(),
12035                Point::new(current_range_start, 0)
12036                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12037                current_range_indent,
12038                current_range_comment_delimiters,
12039                current_range_rewrap_prefix,
12040                from_empty_selection,
12041            ));
12042
12043            ranges
12044        });
12045
12046        let mut edits = Vec::new();
12047        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12048
12049        for (
12050            language_settings,
12051            wrap_range,
12052            mut indent_size,
12053            comment_prefix,
12054            rewrap_prefix,
12055            from_empty_selection,
12056        ) in wrap_ranges
12057        {
12058            let mut start_row = wrap_range.start.row;
12059            let mut end_row = wrap_range.end.row;
12060
12061            // Skip selections that overlap with a range that has already been rewrapped.
12062            let selection_range = start_row..end_row;
12063            if rewrapped_row_ranges
12064                .iter()
12065                .any(|range| range.overlaps(&selection_range))
12066            {
12067                continue;
12068            }
12069
12070            let tab_size = language_settings.tab_size;
12071
12072            let (line_prefix, inside_comment) = match &comment_prefix {
12073                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12074                    (Some(prefix.as_str()), true)
12075                }
12076                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12077                    (Some(prefix.as_ref()), true)
12078                }
12079                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12080                    start: _,
12081                    end: _,
12082                    prefix,
12083                    tab_size,
12084                })) => {
12085                    indent_size.len += tab_size;
12086                    (Some(prefix.as_ref()), true)
12087                }
12088                None => (None, false),
12089            };
12090            let indent_prefix = indent_size.chars().collect::<String>();
12091            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12092
12093            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12094                RewrapBehavior::InComments => inside_comment,
12095                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12096                RewrapBehavior::Anywhere => true,
12097            };
12098
12099            let should_rewrap = options.override_language_settings
12100                || allow_rewrap_based_on_language
12101                || self.hard_wrap.is_some();
12102            if !should_rewrap {
12103                continue;
12104            }
12105
12106            if from_empty_selection {
12107                'expand_upwards: while start_row > 0 {
12108                    let prev_row = start_row - 1;
12109                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12110                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12111                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12112                    {
12113                        start_row = prev_row;
12114                    } else {
12115                        break 'expand_upwards;
12116                    }
12117                }
12118
12119                'expand_downwards: while end_row < buffer.max_point().row {
12120                    let next_row = end_row + 1;
12121                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12122                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12123                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12124                    {
12125                        end_row = next_row;
12126                    } else {
12127                        break 'expand_downwards;
12128                    }
12129                }
12130            }
12131
12132            let start = Point::new(start_row, 0);
12133            let start_offset = start.to_offset(&buffer);
12134            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12135            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12136            let mut first_line_delimiter = None;
12137            let mut last_line_delimiter = None;
12138            let Some(lines_without_prefixes) = selection_text
12139                .lines()
12140                .enumerate()
12141                .map(|(ix, line)| {
12142                    let line_trimmed = line.trim_start();
12143                    if rewrap_prefix.is_some() && ix > 0 {
12144                        Ok(line_trimmed)
12145                    } else if let Some(
12146                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12147                            start,
12148                            prefix,
12149                            end,
12150                            tab_size,
12151                        })
12152                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12153                            start,
12154                            prefix,
12155                            end,
12156                            tab_size,
12157                        }),
12158                    ) = &comment_prefix
12159                    {
12160                        let line_trimmed = line_trimmed
12161                            .strip_prefix(start.as_ref())
12162                            .map(|s| {
12163                                let mut indent_size = indent_size;
12164                                indent_size.len -= tab_size;
12165                                let indent_prefix: String = indent_size.chars().collect();
12166                                first_line_delimiter = Some((indent_prefix, start));
12167                                s.trim_start()
12168                            })
12169                            .unwrap_or(line_trimmed);
12170                        let line_trimmed = line_trimmed
12171                            .strip_suffix(end.as_ref())
12172                            .map(|s| {
12173                                last_line_delimiter = Some(end);
12174                                s.trim_end()
12175                            })
12176                            .unwrap_or(line_trimmed);
12177                        let line_trimmed = line_trimmed
12178                            .strip_prefix(prefix.as_ref())
12179                            .unwrap_or(line_trimmed);
12180                        Ok(line_trimmed)
12181                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12182                        line_trimmed.strip_prefix(prefix).with_context(|| {
12183                            format!("line did not start with prefix {prefix:?}: {line:?}")
12184                        })
12185                    } else {
12186                        line_trimmed
12187                            .strip_prefix(&line_prefix.trim_start())
12188                            .with_context(|| {
12189                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12190                            })
12191                    }
12192                })
12193                .collect::<Result<Vec<_>, _>>()
12194                .log_err()
12195            else {
12196                continue;
12197            };
12198
12199            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12200                buffer
12201                    .language_settings_at(Point::new(start_row, 0), cx)
12202                    .preferred_line_length as usize
12203            });
12204
12205            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12206                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12207            } else {
12208                line_prefix.clone()
12209            };
12210
12211            let wrapped_text = {
12212                let mut wrapped_text = wrap_with_prefix(
12213                    line_prefix,
12214                    subsequent_lines_prefix,
12215                    lines_without_prefixes.join("\n"),
12216                    wrap_column,
12217                    tab_size,
12218                    options.preserve_existing_whitespace,
12219                );
12220
12221                if let Some((indent, delimiter)) = first_line_delimiter {
12222                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12223                }
12224                if let Some(last_line) = last_line_delimiter {
12225                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12226                }
12227
12228                wrapped_text
12229            };
12230
12231            // TODO: should always use char-based diff while still supporting cursor behavior that
12232            // matches vim.
12233            let mut diff_options = DiffOptions::default();
12234            if options.override_language_settings {
12235                diff_options.max_word_diff_len = 0;
12236                diff_options.max_word_diff_line_count = 0;
12237            } else {
12238                diff_options.max_word_diff_len = usize::MAX;
12239                diff_options.max_word_diff_line_count = usize::MAX;
12240            }
12241
12242            for (old_range, new_text) in
12243                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12244            {
12245                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12246                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12247                edits.push((edit_start..edit_end, new_text));
12248            }
12249
12250            rewrapped_row_ranges.push(start_row..=end_row);
12251        }
12252
12253        self.buffer
12254            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12255    }
12256
12257    pub fn cut_common(
12258        &mut self,
12259        cut_no_selection_line: bool,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) -> ClipboardItem {
12263        let mut text = String::new();
12264        let buffer = self.buffer.read(cx).snapshot(cx);
12265        let mut selections = self.selections.all::<Point>(cx);
12266        let mut clipboard_selections = Vec::with_capacity(selections.len());
12267        {
12268            let max_point = buffer.max_point();
12269            let mut is_first = true;
12270            for selection in &mut selections {
12271                let is_entire_line =
12272                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12273                if is_entire_line {
12274                    selection.start = Point::new(selection.start.row, 0);
12275                    if !selection.is_empty() && selection.end.column == 0 {
12276                        selection.end = cmp::min(max_point, selection.end);
12277                    } else {
12278                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12279                    }
12280                    selection.goal = SelectionGoal::None;
12281                }
12282                if is_first {
12283                    is_first = false;
12284                } else {
12285                    text += "\n";
12286                }
12287                let mut len = 0;
12288                for chunk in buffer.text_for_range(selection.start..selection.end) {
12289                    text.push_str(chunk);
12290                    len += chunk.len();
12291                }
12292                clipboard_selections.push(ClipboardSelection {
12293                    len,
12294                    is_entire_line,
12295                    first_line_indent: buffer
12296                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12297                        .len,
12298                });
12299            }
12300        }
12301
12302        self.transact(window, cx, |this, window, cx| {
12303            this.change_selections(Default::default(), window, cx, |s| {
12304                s.select(selections);
12305            });
12306            this.insert("", window, cx);
12307        });
12308        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12309    }
12310
12311    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12313        let item = self.cut_common(true, window, cx);
12314        cx.write_to_clipboard(item);
12315    }
12316
12317    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12319        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12320            s.move_with(|snapshot, sel| {
12321                if sel.is_empty() {
12322                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12323                }
12324                if sel.is_empty() {
12325                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12326                }
12327            });
12328        });
12329        let item = self.cut_common(true, window, cx);
12330        cx.set_global(KillRing(item))
12331    }
12332
12333    pub fn kill_ring_yank(
12334        &mut self,
12335        _: &KillRingYank,
12336        window: &mut Window,
12337        cx: &mut Context<Self>,
12338    ) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12340        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12341            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12342                (kill_ring.text().to_string(), kill_ring.metadata_json())
12343            } else {
12344                return;
12345            }
12346        } else {
12347            return;
12348        };
12349        self.do_paste(&text, metadata, false, window, cx);
12350    }
12351
12352    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12353        self.do_copy(true, cx);
12354    }
12355
12356    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12357        self.do_copy(false, cx);
12358    }
12359
12360    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12361        let selections = self.selections.all::<Point>(cx);
12362        let buffer = self.buffer.read(cx).read(cx);
12363        let mut text = String::new();
12364
12365        let mut clipboard_selections = Vec::with_capacity(selections.len());
12366        {
12367            let max_point = buffer.max_point();
12368            let mut is_first = true;
12369            for selection in &selections {
12370                let mut start = selection.start;
12371                let mut end = selection.end;
12372                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12373                if is_entire_line {
12374                    start = Point::new(start.row, 0);
12375                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12376                }
12377
12378                let mut trimmed_selections = Vec::new();
12379                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12380                    let row = MultiBufferRow(start.row);
12381                    let first_indent = buffer.indent_size_for_line(row);
12382                    if first_indent.len == 0 || start.column > first_indent.len {
12383                        trimmed_selections.push(start..end);
12384                    } else {
12385                        trimmed_selections.push(
12386                            Point::new(row.0, first_indent.len)
12387                                ..Point::new(row.0, buffer.line_len(row)),
12388                        );
12389                        for row in start.row + 1..=end.row {
12390                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12391                            if row == end.row {
12392                                line_len = end.column;
12393                            }
12394                            if line_len == 0 {
12395                                trimmed_selections
12396                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12397                                continue;
12398                            }
12399                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12400                            if row_indent_size.len >= first_indent.len {
12401                                trimmed_selections.push(
12402                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12403                                );
12404                            } else {
12405                                trimmed_selections.clear();
12406                                trimmed_selections.push(start..end);
12407                                break;
12408                            }
12409                        }
12410                    }
12411                } else {
12412                    trimmed_selections.push(start..end);
12413                }
12414
12415                for trimmed_range in trimmed_selections {
12416                    if is_first {
12417                        is_first = false;
12418                    } else {
12419                        text += "\n";
12420                    }
12421                    let mut len = 0;
12422                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12423                        text.push_str(chunk);
12424                        len += chunk.len();
12425                    }
12426                    clipboard_selections.push(ClipboardSelection {
12427                        len,
12428                        is_entire_line,
12429                        first_line_indent: buffer
12430                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12431                            .len,
12432                    });
12433                }
12434            }
12435        }
12436
12437        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12438            text,
12439            clipboard_selections,
12440        ));
12441    }
12442
12443    pub fn do_paste(
12444        &mut self,
12445        text: &String,
12446        clipboard_selections: Option<Vec<ClipboardSelection>>,
12447        handle_entire_lines: bool,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        if self.read_only(cx) {
12452            return;
12453        }
12454
12455        let clipboard_text = Cow::Borrowed(text);
12456
12457        self.transact(window, cx, |this, window, cx| {
12458            let had_active_edit_prediction = this.has_active_edit_prediction();
12459
12460            if let Some(mut clipboard_selections) = clipboard_selections {
12461                let old_selections = this.selections.all::<usize>(cx);
12462                let all_selections_were_entire_line =
12463                    clipboard_selections.iter().all(|s| s.is_entire_line);
12464                let first_selection_indent_column =
12465                    clipboard_selections.first().map(|s| s.first_line_indent);
12466                if clipboard_selections.len() != old_selections.len() {
12467                    clipboard_selections.drain(..);
12468                }
12469                let cursor_offset = this.selections.last::<usize>(cx).head();
12470                let mut auto_indent_on_paste = true;
12471
12472                this.buffer.update(cx, |buffer, cx| {
12473                    let snapshot = buffer.read(cx);
12474                    auto_indent_on_paste = snapshot
12475                        .language_settings_at(cursor_offset, cx)
12476                        .auto_indent_on_paste;
12477
12478                    let mut start_offset = 0;
12479                    let mut edits = Vec::new();
12480                    let mut original_indent_columns = Vec::new();
12481                    for (ix, selection) in old_selections.iter().enumerate() {
12482                        let to_insert;
12483                        let entire_line;
12484                        let original_indent_column;
12485                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12486                            let end_offset = start_offset + clipboard_selection.len;
12487                            to_insert = &clipboard_text[start_offset..end_offset];
12488                            entire_line = clipboard_selection.is_entire_line;
12489                            start_offset = end_offset + 1;
12490                            original_indent_column = Some(clipboard_selection.first_line_indent);
12491                        } else {
12492                            to_insert = clipboard_text.as_str();
12493                            entire_line = all_selections_were_entire_line;
12494                            original_indent_column = first_selection_indent_column
12495                        }
12496
12497                        // If the corresponding selection was empty when this slice of the
12498                        // clipboard text was written, then the entire line containing the
12499                        // selection was copied. If this selection is also currently empty,
12500                        // then paste the line before the current line of the buffer.
12501                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12502                            let column = selection.start.to_point(&snapshot).column as usize;
12503                            let line_start = selection.start - column;
12504                            line_start..line_start
12505                        } else {
12506                            selection.range()
12507                        };
12508
12509                        edits.push((range, to_insert));
12510                        original_indent_columns.push(original_indent_column);
12511                    }
12512                    drop(snapshot);
12513
12514                    buffer.edit(
12515                        edits,
12516                        if auto_indent_on_paste {
12517                            Some(AutoindentMode::Block {
12518                                original_indent_columns,
12519                            })
12520                        } else {
12521                            None
12522                        },
12523                        cx,
12524                    );
12525                });
12526
12527                let selections = this.selections.all::<usize>(cx);
12528                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12529            } else {
12530                this.insert(&clipboard_text, window, cx);
12531            }
12532
12533            let trigger_in_words =
12534                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12535
12536            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12537        });
12538    }
12539
12540    pub fn diff_clipboard_with_selection(
12541        &mut self,
12542        _: &DiffClipboardWithSelection,
12543        window: &mut Window,
12544        cx: &mut Context<Self>,
12545    ) {
12546        let selections = self.selections.all::<usize>(cx);
12547
12548        if selections.is_empty() {
12549            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12550            return;
12551        };
12552
12553        let clipboard_text = match cx.read_from_clipboard() {
12554            Some(item) => match item.entries().first() {
12555                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12556                _ => None,
12557            },
12558            None => None,
12559        };
12560
12561        let Some(clipboard_text) = clipboard_text else {
12562            log::warn!("Clipboard doesn't contain text.");
12563            return;
12564        };
12565
12566        window.dispatch_action(
12567            Box::new(DiffClipboardWithSelectionData {
12568                clipboard_text,
12569                editor: cx.entity(),
12570            }),
12571            cx,
12572        );
12573    }
12574
12575    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12576        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12577        if let Some(item) = cx.read_from_clipboard() {
12578            let entries = item.entries();
12579
12580            match entries.first() {
12581                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12582                // of all the pasted entries.
12583                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12584                    .do_paste(
12585                        clipboard_string.text(),
12586                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12587                        true,
12588                        window,
12589                        cx,
12590                    ),
12591                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12592            }
12593        }
12594    }
12595
12596    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12597        if self.read_only(cx) {
12598            return;
12599        }
12600
12601        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12602
12603        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12604            if let Some((selections, _)) =
12605                self.selection_history.transaction(transaction_id).cloned()
12606            {
12607                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12608                    s.select_anchors(selections.to_vec());
12609                });
12610            } else {
12611                log::error!(
12612                    "No entry in selection_history found for undo. \
12613                     This may correspond to a bug where undo does not update the selection. \
12614                     If this is occurring, please add details to \
12615                     https://github.com/zed-industries/zed/issues/22692"
12616                );
12617            }
12618            self.request_autoscroll(Autoscroll::fit(), cx);
12619            self.unmark_text(window, cx);
12620            self.refresh_edit_prediction(true, false, window, cx);
12621            cx.emit(EditorEvent::Edited { transaction_id });
12622            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12623        }
12624    }
12625
12626    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12627        if self.read_only(cx) {
12628            return;
12629        }
12630
12631        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12632
12633        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12634            if let Some((_, Some(selections))) =
12635                self.selection_history.transaction(transaction_id).cloned()
12636            {
12637                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12638                    s.select_anchors(selections.to_vec());
12639                });
12640            } else {
12641                log::error!(
12642                    "No entry in selection_history found for redo. \
12643                     This may correspond to a bug where undo does not update the selection. \
12644                     If this is occurring, please add details to \
12645                     https://github.com/zed-industries/zed/issues/22692"
12646                );
12647            }
12648            self.request_autoscroll(Autoscroll::fit(), cx);
12649            self.unmark_text(window, cx);
12650            self.refresh_edit_prediction(true, false, window, cx);
12651            cx.emit(EditorEvent::Edited { transaction_id });
12652        }
12653    }
12654
12655    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12656        self.buffer
12657            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12658    }
12659
12660    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12661        self.buffer
12662            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12663    }
12664
12665    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12667        self.change_selections(Default::default(), window, cx, |s| {
12668            s.move_with(|map, selection| {
12669                let cursor = if selection.is_empty() {
12670                    movement::left(map, selection.start)
12671                } else {
12672                    selection.start
12673                };
12674                selection.collapse_to(cursor, SelectionGoal::None);
12675            });
12676        })
12677    }
12678
12679    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12681        self.change_selections(Default::default(), window, cx, |s| {
12682            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12683        })
12684    }
12685
12686    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12687        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12688        self.change_selections(Default::default(), window, cx, |s| {
12689            s.move_with(|map, selection| {
12690                let cursor = if selection.is_empty() {
12691                    movement::right(map, selection.end)
12692                } else {
12693                    selection.end
12694                };
12695                selection.collapse_to(cursor, SelectionGoal::None)
12696            });
12697        })
12698    }
12699
12700    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12701        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12702        self.change_selections(Default::default(), window, cx, |s| {
12703            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12704        })
12705    }
12706
12707    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12708        if self.take_rename(true, window, cx).is_some() {
12709            return;
12710        }
12711
12712        if self.mode.is_single_line() {
12713            cx.propagate();
12714            return;
12715        }
12716
12717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12718
12719        let text_layout_details = &self.text_layout_details(window);
12720        let selection_count = self.selections.count();
12721        let first_selection = self.selections.first_anchor();
12722
12723        self.change_selections(Default::default(), window, cx, |s| {
12724            s.move_with(|map, selection| {
12725                if !selection.is_empty() {
12726                    selection.goal = SelectionGoal::None;
12727                }
12728                let (cursor, goal) = movement::up(
12729                    map,
12730                    selection.start,
12731                    selection.goal,
12732                    false,
12733                    text_layout_details,
12734                );
12735                selection.collapse_to(cursor, goal);
12736            });
12737        });
12738
12739        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12740        {
12741            cx.propagate();
12742        }
12743    }
12744
12745    pub fn move_up_by_lines(
12746        &mut self,
12747        action: &MoveUpByLines,
12748        window: &mut Window,
12749        cx: &mut Context<Self>,
12750    ) {
12751        if self.take_rename(true, window, cx).is_some() {
12752            return;
12753        }
12754
12755        if self.mode.is_single_line() {
12756            cx.propagate();
12757            return;
12758        }
12759
12760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12761
12762        let text_layout_details = &self.text_layout_details(window);
12763
12764        self.change_selections(Default::default(), window, cx, |s| {
12765            s.move_with(|map, selection| {
12766                if !selection.is_empty() {
12767                    selection.goal = SelectionGoal::None;
12768                }
12769                let (cursor, goal) = movement::up_by_rows(
12770                    map,
12771                    selection.start,
12772                    action.lines,
12773                    selection.goal,
12774                    false,
12775                    text_layout_details,
12776                );
12777                selection.collapse_to(cursor, goal);
12778            });
12779        })
12780    }
12781
12782    pub fn move_down_by_lines(
12783        &mut self,
12784        action: &MoveDownByLines,
12785        window: &mut Window,
12786        cx: &mut Context<Self>,
12787    ) {
12788        if self.take_rename(true, window, cx).is_some() {
12789            return;
12790        }
12791
12792        if self.mode.is_single_line() {
12793            cx.propagate();
12794            return;
12795        }
12796
12797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12798
12799        let text_layout_details = &self.text_layout_details(window);
12800
12801        self.change_selections(Default::default(), window, cx, |s| {
12802            s.move_with(|map, selection| {
12803                if !selection.is_empty() {
12804                    selection.goal = SelectionGoal::None;
12805                }
12806                let (cursor, goal) = movement::down_by_rows(
12807                    map,
12808                    selection.start,
12809                    action.lines,
12810                    selection.goal,
12811                    false,
12812                    text_layout_details,
12813                );
12814                selection.collapse_to(cursor, goal);
12815            });
12816        })
12817    }
12818
12819    pub fn select_down_by_lines(
12820        &mut self,
12821        action: &SelectDownByLines,
12822        window: &mut Window,
12823        cx: &mut Context<Self>,
12824    ) {
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12826        let text_layout_details = &self.text_layout_details(window);
12827        self.change_selections(Default::default(), window, cx, |s| {
12828            s.move_heads_with(|map, head, goal| {
12829                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12830            })
12831        })
12832    }
12833
12834    pub fn select_up_by_lines(
12835        &mut self,
12836        action: &SelectUpByLines,
12837        window: &mut Window,
12838        cx: &mut Context<Self>,
12839    ) {
12840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12841        let text_layout_details = &self.text_layout_details(window);
12842        self.change_selections(Default::default(), window, cx, |s| {
12843            s.move_heads_with(|map, head, goal| {
12844                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12845            })
12846        })
12847    }
12848
12849    pub fn select_page_up(
12850        &mut self,
12851        _: &SelectPageUp,
12852        window: &mut Window,
12853        cx: &mut Context<Self>,
12854    ) {
12855        let Some(row_count) = self.visible_row_count() else {
12856            return;
12857        };
12858
12859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12860
12861        let text_layout_details = &self.text_layout_details(window);
12862
12863        self.change_selections(Default::default(), window, cx, |s| {
12864            s.move_heads_with(|map, head, goal| {
12865                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12866            })
12867        })
12868    }
12869
12870    pub fn move_page_up(
12871        &mut self,
12872        action: &MovePageUp,
12873        window: &mut Window,
12874        cx: &mut Context<Self>,
12875    ) {
12876        if self.take_rename(true, window, cx).is_some() {
12877            return;
12878        }
12879
12880        if self
12881            .context_menu
12882            .borrow_mut()
12883            .as_mut()
12884            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12885            .unwrap_or(false)
12886        {
12887            return;
12888        }
12889
12890        if matches!(self.mode, EditorMode::SingleLine) {
12891            cx.propagate();
12892            return;
12893        }
12894
12895        let Some(row_count) = self.visible_row_count() else {
12896            return;
12897        };
12898
12899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12900
12901        let effects = if action.center_cursor {
12902            SelectionEffects::scroll(Autoscroll::center())
12903        } else {
12904            SelectionEffects::default()
12905        };
12906
12907        let text_layout_details = &self.text_layout_details(window);
12908
12909        self.change_selections(effects, window, cx, |s| {
12910            s.move_with(|map, selection| {
12911                if !selection.is_empty() {
12912                    selection.goal = SelectionGoal::None;
12913                }
12914                let (cursor, goal) = movement::up_by_rows(
12915                    map,
12916                    selection.end,
12917                    row_count,
12918                    selection.goal,
12919                    false,
12920                    text_layout_details,
12921                );
12922                selection.collapse_to(cursor, goal);
12923            });
12924        });
12925    }
12926
12927    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12929        let text_layout_details = &self.text_layout_details(window);
12930        self.change_selections(Default::default(), window, cx, |s| {
12931            s.move_heads_with(|map, head, goal| {
12932                movement::up(map, head, goal, false, text_layout_details)
12933            })
12934        })
12935    }
12936
12937    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12938        self.take_rename(true, window, cx);
12939
12940        if self.mode.is_single_line() {
12941            cx.propagate();
12942            return;
12943        }
12944
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12946
12947        let text_layout_details = &self.text_layout_details(window);
12948        let selection_count = self.selections.count();
12949        let first_selection = self.selections.first_anchor();
12950
12951        self.change_selections(Default::default(), window, cx, |s| {
12952            s.move_with(|map, selection| {
12953                if !selection.is_empty() {
12954                    selection.goal = SelectionGoal::None;
12955                }
12956                let (cursor, goal) = movement::down(
12957                    map,
12958                    selection.end,
12959                    selection.goal,
12960                    false,
12961                    text_layout_details,
12962                );
12963                selection.collapse_to(cursor, goal);
12964            });
12965        });
12966
12967        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12968        {
12969            cx.propagate();
12970        }
12971    }
12972
12973    pub fn select_page_down(
12974        &mut self,
12975        _: &SelectPageDown,
12976        window: &mut Window,
12977        cx: &mut Context<Self>,
12978    ) {
12979        let Some(row_count) = self.visible_row_count() else {
12980            return;
12981        };
12982
12983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12984
12985        let text_layout_details = &self.text_layout_details(window);
12986
12987        self.change_selections(Default::default(), window, cx, |s| {
12988            s.move_heads_with(|map, head, goal| {
12989                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12990            })
12991        })
12992    }
12993
12994    pub fn move_page_down(
12995        &mut self,
12996        action: &MovePageDown,
12997        window: &mut Window,
12998        cx: &mut Context<Self>,
12999    ) {
13000        if self.take_rename(true, window, cx).is_some() {
13001            return;
13002        }
13003
13004        if self
13005            .context_menu
13006            .borrow_mut()
13007            .as_mut()
13008            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13009            .unwrap_or(false)
13010        {
13011            return;
13012        }
13013
13014        if matches!(self.mode, EditorMode::SingleLine) {
13015            cx.propagate();
13016            return;
13017        }
13018
13019        let Some(row_count) = self.visible_row_count() else {
13020            return;
13021        };
13022
13023        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13024
13025        let effects = if action.center_cursor {
13026            SelectionEffects::scroll(Autoscroll::center())
13027        } else {
13028            SelectionEffects::default()
13029        };
13030
13031        let text_layout_details = &self.text_layout_details(window);
13032        self.change_selections(effects, window, cx, |s| {
13033            s.move_with(|map, selection| {
13034                if !selection.is_empty() {
13035                    selection.goal = SelectionGoal::None;
13036                }
13037                let (cursor, goal) = movement::down_by_rows(
13038                    map,
13039                    selection.end,
13040                    row_count,
13041                    selection.goal,
13042                    false,
13043                    text_layout_details,
13044                );
13045                selection.collapse_to(cursor, goal);
13046            });
13047        });
13048    }
13049
13050    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13051        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13052        let text_layout_details = &self.text_layout_details(window);
13053        self.change_selections(Default::default(), window, cx, |s| {
13054            s.move_heads_with(|map, head, goal| {
13055                movement::down(map, head, goal, false, text_layout_details)
13056            })
13057        });
13058    }
13059
13060    pub fn context_menu_first(
13061        &mut self,
13062        _: &ContextMenuFirst,
13063        window: &mut Window,
13064        cx: &mut Context<Self>,
13065    ) {
13066        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13067            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13068        }
13069    }
13070
13071    pub fn context_menu_prev(
13072        &mut self,
13073        _: &ContextMenuPrevious,
13074        window: &mut Window,
13075        cx: &mut Context<Self>,
13076    ) {
13077        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13078            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13079        }
13080    }
13081
13082    pub fn context_menu_next(
13083        &mut self,
13084        _: &ContextMenuNext,
13085        window: &mut Window,
13086        cx: &mut Context<Self>,
13087    ) {
13088        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13089            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13090        }
13091    }
13092
13093    pub fn context_menu_last(
13094        &mut self,
13095        _: &ContextMenuLast,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13100            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13101        }
13102    }
13103
13104    pub fn signature_help_prev(
13105        &mut self,
13106        _: &SignatureHelpPrevious,
13107        _: &mut Window,
13108        cx: &mut Context<Self>,
13109    ) {
13110        if let Some(popover) = self.signature_help_state.popover_mut() {
13111            if popover.current_signature == 0 {
13112                popover.current_signature = popover.signatures.len() - 1;
13113            } else {
13114                popover.current_signature -= 1;
13115            }
13116            cx.notify();
13117        }
13118    }
13119
13120    pub fn signature_help_next(
13121        &mut self,
13122        _: &SignatureHelpNext,
13123        _: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        if let Some(popover) = self.signature_help_state.popover_mut() {
13127            if popover.current_signature + 1 == popover.signatures.len() {
13128                popover.current_signature = 0;
13129            } else {
13130                popover.current_signature += 1;
13131            }
13132            cx.notify();
13133        }
13134    }
13135
13136    pub fn move_to_previous_word_start(
13137        &mut self,
13138        _: &MoveToPreviousWordStart,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13143        self.change_selections(Default::default(), window, cx, |s| {
13144            s.move_cursors_with(|map, head, _| {
13145                (
13146                    movement::previous_word_start(map, head),
13147                    SelectionGoal::None,
13148                )
13149            });
13150        })
13151    }
13152
13153    pub fn move_to_previous_subword_start(
13154        &mut self,
13155        _: &MoveToPreviousSubwordStart,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13160        self.change_selections(Default::default(), window, cx, |s| {
13161            s.move_cursors_with(|map, head, _| {
13162                (
13163                    movement::previous_subword_start(map, head),
13164                    SelectionGoal::None,
13165                )
13166            });
13167        })
13168    }
13169
13170    pub fn select_to_previous_word_start(
13171        &mut self,
13172        _: &SelectToPreviousWordStart,
13173        window: &mut Window,
13174        cx: &mut Context<Self>,
13175    ) {
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13177        self.change_selections(Default::default(), window, cx, |s| {
13178            s.move_heads_with(|map, head, _| {
13179                (
13180                    movement::previous_word_start(map, head),
13181                    SelectionGoal::None,
13182                )
13183            });
13184        })
13185    }
13186
13187    pub fn select_to_previous_subword_start(
13188        &mut self,
13189        _: &SelectToPreviousSubwordStart,
13190        window: &mut Window,
13191        cx: &mut Context<Self>,
13192    ) {
13193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13194        self.change_selections(Default::default(), window, cx, |s| {
13195            s.move_heads_with(|map, head, _| {
13196                (
13197                    movement::previous_subword_start(map, head),
13198                    SelectionGoal::None,
13199                )
13200            });
13201        })
13202    }
13203
13204    pub fn delete_to_previous_word_start(
13205        &mut self,
13206        action: &DeleteToPreviousWordStart,
13207        window: &mut Window,
13208        cx: &mut Context<Self>,
13209    ) {
13210        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13211        self.transact(window, cx, |this, window, cx| {
13212            this.select_autoclose_pair(window, cx);
13213            this.change_selections(Default::default(), window, cx, |s| {
13214                s.move_with(|map, selection| {
13215                    if selection.is_empty() {
13216                        let mut cursor = if action.ignore_newlines {
13217                            movement::previous_word_start(map, selection.head())
13218                        } else {
13219                            movement::previous_word_start_or_newline(map, selection.head())
13220                        };
13221                        cursor = movement::adjust_greedy_deletion(
13222                            map,
13223                            selection.head(),
13224                            cursor,
13225                            action.ignore_brackets,
13226                        );
13227                        selection.set_head(cursor, SelectionGoal::None);
13228                    }
13229                });
13230            });
13231            this.insert("", window, cx);
13232        });
13233    }
13234
13235    pub fn delete_to_previous_subword_start(
13236        &mut self,
13237        _: &DeleteToPreviousSubwordStart,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13242        self.transact(window, cx, |this, window, cx| {
13243            this.select_autoclose_pair(window, cx);
13244            this.change_selections(Default::default(), window, cx, |s| {
13245                s.move_with(|map, selection| {
13246                    if selection.is_empty() {
13247                        let mut cursor = movement::previous_subword_start(map, selection.head());
13248                        cursor =
13249                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13250                        selection.set_head(cursor, SelectionGoal::None);
13251                    }
13252                });
13253            });
13254            this.insert("", window, cx);
13255        });
13256    }
13257
13258    pub fn move_to_next_word_end(
13259        &mut self,
13260        _: &MoveToNextWordEnd,
13261        window: &mut Window,
13262        cx: &mut Context<Self>,
13263    ) {
13264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13265        self.change_selections(Default::default(), window, cx, |s| {
13266            s.move_cursors_with(|map, head, _| {
13267                (movement::next_word_end(map, head), SelectionGoal::None)
13268            });
13269        })
13270    }
13271
13272    pub fn move_to_next_subword_end(
13273        &mut self,
13274        _: &MoveToNextSubwordEnd,
13275        window: &mut Window,
13276        cx: &mut Context<Self>,
13277    ) {
13278        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13279        self.change_selections(Default::default(), window, cx, |s| {
13280            s.move_cursors_with(|map, head, _| {
13281                (movement::next_subword_end(map, head), SelectionGoal::None)
13282            });
13283        })
13284    }
13285
13286    pub fn select_to_next_word_end(
13287        &mut self,
13288        _: &SelectToNextWordEnd,
13289        window: &mut Window,
13290        cx: &mut Context<Self>,
13291    ) {
13292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13293        self.change_selections(Default::default(), window, cx, |s| {
13294            s.move_heads_with(|map, head, _| {
13295                (movement::next_word_end(map, head), SelectionGoal::None)
13296            });
13297        })
13298    }
13299
13300    pub fn select_to_next_subword_end(
13301        &mut self,
13302        _: &SelectToNextSubwordEnd,
13303        window: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13307        self.change_selections(Default::default(), window, cx, |s| {
13308            s.move_heads_with(|map, head, _| {
13309                (movement::next_subword_end(map, head), SelectionGoal::None)
13310            });
13311        })
13312    }
13313
13314    pub fn delete_to_next_word_end(
13315        &mut self,
13316        action: &DeleteToNextWordEnd,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13321        self.transact(window, cx, |this, window, cx| {
13322            this.change_selections(Default::default(), window, cx, |s| {
13323                s.move_with(|map, selection| {
13324                    if selection.is_empty() {
13325                        let mut cursor = if action.ignore_newlines {
13326                            movement::next_word_end(map, selection.head())
13327                        } else {
13328                            movement::next_word_end_or_newline(map, selection.head())
13329                        };
13330                        cursor = movement::adjust_greedy_deletion(
13331                            map,
13332                            selection.head(),
13333                            cursor,
13334                            action.ignore_brackets,
13335                        );
13336                        selection.set_head(cursor, SelectionGoal::None);
13337                    }
13338                });
13339            });
13340            this.insert("", window, cx);
13341        });
13342    }
13343
13344    pub fn delete_to_next_subword_end(
13345        &mut self,
13346        _: &DeleteToNextSubwordEnd,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13351        self.transact(window, cx, |this, window, cx| {
13352            this.change_selections(Default::default(), window, cx, |s| {
13353                s.move_with(|map, selection| {
13354                    if selection.is_empty() {
13355                        let mut cursor = movement::next_subword_end(map, selection.head());
13356                        cursor =
13357                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13358                        selection.set_head(cursor, SelectionGoal::None);
13359                    }
13360                });
13361            });
13362            this.insert("", window, cx);
13363        });
13364    }
13365
13366    pub fn move_to_beginning_of_line(
13367        &mut self,
13368        action: &MoveToBeginningOfLine,
13369        window: &mut Window,
13370        cx: &mut Context<Self>,
13371    ) {
13372        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13373        self.change_selections(Default::default(), window, cx, |s| {
13374            s.move_cursors_with(|map, head, _| {
13375                (
13376                    movement::indented_line_beginning(
13377                        map,
13378                        head,
13379                        action.stop_at_soft_wraps,
13380                        action.stop_at_indent,
13381                    ),
13382                    SelectionGoal::None,
13383                )
13384            });
13385        })
13386    }
13387
13388    pub fn select_to_beginning_of_line(
13389        &mut self,
13390        action: &SelectToBeginningOfLine,
13391        window: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13395        self.change_selections(Default::default(), window, cx, |s| {
13396            s.move_heads_with(|map, head, _| {
13397                (
13398                    movement::indented_line_beginning(
13399                        map,
13400                        head,
13401                        action.stop_at_soft_wraps,
13402                        action.stop_at_indent,
13403                    ),
13404                    SelectionGoal::None,
13405                )
13406            });
13407        });
13408    }
13409
13410    pub fn delete_to_beginning_of_line(
13411        &mut self,
13412        action: &DeleteToBeginningOfLine,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) {
13416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13417        self.transact(window, cx, |this, window, cx| {
13418            this.change_selections(Default::default(), window, cx, |s| {
13419                s.move_with(|_, selection| {
13420                    selection.reversed = true;
13421                });
13422            });
13423
13424            this.select_to_beginning_of_line(
13425                &SelectToBeginningOfLine {
13426                    stop_at_soft_wraps: false,
13427                    stop_at_indent: action.stop_at_indent,
13428                },
13429                window,
13430                cx,
13431            );
13432            this.backspace(&Backspace, window, cx);
13433        });
13434    }
13435
13436    pub fn move_to_end_of_line(
13437        &mut self,
13438        action: &MoveToEndOfLine,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13443        self.change_selections(Default::default(), window, cx, |s| {
13444            s.move_cursors_with(|map, head, _| {
13445                (
13446                    movement::line_end(map, head, action.stop_at_soft_wraps),
13447                    SelectionGoal::None,
13448                )
13449            });
13450        })
13451    }
13452
13453    pub fn select_to_end_of_line(
13454        &mut self,
13455        action: &SelectToEndOfLine,
13456        window: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13460        self.change_selections(Default::default(), window, cx, |s| {
13461            s.move_heads_with(|map, head, _| {
13462                (
13463                    movement::line_end(map, head, action.stop_at_soft_wraps),
13464                    SelectionGoal::None,
13465                )
13466            });
13467        })
13468    }
13469
13470    pub fn delete_to_end_of_line(
13471        &mut self,
13472        _: &DeleteToEndOfLine,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13477        self.transact(window, cx, |this, window, cx| {
13478            this.select_to_end_of_line(
13479                &SelectToEndOfLine {
13480                    stop_at_soft_wraps: false,
13481                },
13482                window,
13483                cx,
13484            );
13485            this.delete(&Delete, window, cx);
13486        });
13487    }
13488
13489    pub fn cut_to_end_of_line(
13490        &mut self,
13491        action: &CutToEndOfLine,
13492        window: &mut Window,
13493        cx: &mut Context<Self>,
13494    ) {
13495        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13496        self.transact(window, cx, |this, window, cx| {
13497            this.select_to_end_of_line(
13498                &SelectToEndOfLine {
13499                    stop_at_soft_wraps: false,
13500                },
13501                window,
13502                cx,
13503            );
13504            if !action.stop_at_newlines {
13505                this.change_selections(Default::default(), window, cx, |s| {
13506                    s.move_with(|_, sel| {
13507                        if sel.is_empty() {
13508                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13509                        }
13510                    });
13511                });
13512            }
13513            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13514            let item = this.cut_common(false, window, cx);
13515            cx.write_to_clipboard(item);
13516        });
13517    }
13518
13519    pub fn move_to_start_of_paragraph(
13520        &mut self,
13521        _: &MoveToStartOfParagraph,
13522        window: &mut Window,
13523        cx: &mut Context<Self>,
13524    ) {
13525        if matches!(self.mode, EditorMode::SingleLine) {
13526            cx.propagate();
13527            return;
13528        }
13529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13530        self.change_selections(Default::default(), window, cx, |s| {
13531            s.move_with(|map, selection| {
13532                selection.collapse_to(
13533                    movement::start_of_paragraph(map, selection.head(), 1),
13534                    SelectionGoal::None,
13535                )
13536            });
13537        })
13538    }
13539
13540    pub fn move_to_end_of_paragraph(
13541        &mut self,
13542        _: &MoveToEndOfParagraph,
13543        window: &mut Window,
13544        cx: &mut Context<Self>,
13545    ) {
13546        if matches!(self.mode, EditorMode::SingleLine) {
13547            cx.propagate();
13548            return;
13549        }
13550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13551        self.change_selections(Default::default(), window, cx, |s| {
13552            s.move_with(|map, selection| {
13553                selection.collapse_to(
13554                    movement::end_of_paragraph(map, selection.head(), 1),
13555                    SelectionGoal::None,
13556                )
13557            });
13558        })
13559    }
13560
13561    pub fn select_to_start_of_paragraph(
13562        &mut self,
13563        _: &SelectToStartOfParagraph,
13564        window: &mut Window,
13565        cx: &mut Context<Self>,
13566    ) {
13567        if matches!(self.mode, EditorMode::SingleLine) {
13568            cx.propagate();
13569            return;
13570        }
13571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13572        self.change_selections(Default::default(), window, cx, |s| {
13573            s.move_heads_with(|map, head, _| {
13574                (
13575                    movement::start_of_paragraph(map, head, 1),
13576                    SelectionGoal::None,
13577                )
13578            });
13579        })
13580    }
13581
13582    pub fn select_to_end_of_paragraph(
13583        &mut self,
13584        _: &SelectToEndOfParagraph,
13585        window: &mut Window,
13586        cx: &mut Context<Self>,
13587    ) {
13588        if matches!(self.mode, EditorMode::SingleLine) {
13589            cx.propagate();
13590            return;
13591        }
13592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13593        self.change_selections(Default::default(), window, cx, |s| {
13594            s.move_heads_with(|map, head, _| {
13595                (
13596                    movement::end_of_paragraph(map, head, 1),
13597                    SelectionGoal::None,
13598                )
13599            });
13600        })
13601    }
13602
13603    pub fn move_to_start_of_excerpt(
13604        &mut self,
13605        _: &MoveToStartOfExcerpt,
13606        window: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        if matches!(self.mode, EditorMode::SingleLine) {
13610            cx.propagate();
13611            return;
13612        }
13613        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13614        self.change_selections(Default::default(), window, cx, |s| {
13615            s.move_with(|map, selection| {
13616                selection.collapse_to(
13617                    movement::start_of_excerpt(
13618                        map,
13619                        selection.head(),
13620                        workspace::searchable::Direction::Prev,
13621                    ),
13622                    SelectionGoal::None,
13623                )
13624            });
13625        })
13626    }
13627
13628    pub fn move_to_start_of_next_excerpt(
13629        &mut self,
13630        _: &MoveToStartOfNextExcerpt,
13631        window: &mut Window,
13632        cx: &mut Context<Self>,
13633    ) {
13634        if matches!(self.mode, EditorMode::SingleLine) {
13635            cx.propagate();
13636            return;
13637        }
13638
13639        self.change_selections(Default::default(), window, cx, |s| {
13640            s.move_with(|map, selection| {
13641                selection.collapse_to(
13642                    movement::start_of_excerpt(
13643                        map,
13644                        selection.head(),
13645                        workspace::searchable::Direction::Next,
13646                    ),
13647                    SelectionGoal::None,
13648                )
13649            });
13650        })
13651    }
13652
13653    pub fn move_to_end_of_excerpt(
13654        &mut self,
13655        _: &MoveToEndOfExcerpt,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        if matches!(self.mode, EditorMode::SingleLine) {
13660            cx.propagate();
13661            return;
13662        }
13663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13664        self.change_selections(Default::default(), window, cx, |s| {
13665            s.move_with(|map, selection| {
13666                selection.collapse_to(
13667                    movement::end_of_excerpt(
13668                        map,
13669                        selection.head(),
13670                        workspace::searchable::Direction::Next,
13671                    ),
13672                    SelectionGoal::None,
13673                )
13674            });
13675        })
13676    }
13677
13678    pub fn move_to_end_of_previous_excerpt(
13679        &mut self,
13680        _: &MoveToEndOfPreviousExcerpt,
13681        window: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        if matches!(self.mode, EditorMode::SingleLine) {
13685            cx.propagate();
13686            return;
13687        }
13688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13689        self.change_selections(Default::default(), window, cx, |s| {
13690            s.move_with(|map, selection| {
13691                selection.collapse_to(
13692                    movement::end_of_excerpt(
13693                        map,
13694                        selection.head(),
13695                        workspace::searchable::Direction::Prev,
13696                    ),
13697                    SelectionGoal::None,
13698                )
13699            });
13700        })
13701    }
13702
13703    pub fn select_to_start_of_excerpt(
13704        &mut self,
13705        _: &SelectToStartOfExcerpt,
13706        window: &mut Window,
13707        cx: &mut Context<Self>,
13708    ) {
13709        if matches!(self.mode, EditorMode::SingleLine) {
13710            cx.propagate();
13711            return;
13712        }
13713        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13714        self.change_selections(Default::default(), window, cx, |s| {
13715            s.move_heads_with(|map, head, _| {
13716                (
13717                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13718                    SelectionGoal::None,
13719                )
13720            });
13721        })
13722    }
13723
13724    pub fn select_to_start_of_next_excerpt(
13725        &mut self,
13726        _: &SelectToStartOfNextExcerpt,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        if matches!(self.mode, EditorMode::SingleLine) {
13731            cx.propagate();
13732            return;
13733        }
13734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13735        self.change_selections(Default::default(), window, cx, |s| {
13736            s.move_heads_with(|map, head, _| {
13737                (
13738                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13739                    SelectionGoal::None,
13740                )
13741            });
13742        })
13743    }
13744
13745    pub fn select_to_end_of_excerpt(
13746        &mut self,
13747        _: &SelectToEndOfExcerpt,
13748        window: &mut Window,
13749        cx: &mut Context<Self>,
13750    ) {
13751        if matches!(self.mode, EditorMode::SingleLine) {
13752            cx.propagate();
13753            return;
13754        }
13755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13756        self.change_selections(Default::default(), window, cx, |s| {
13757            s.move_heads_with(|map, head, _| {
13758                (
13759                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13760                    SelectionGoal::None,
13761                )
13762            });
13763        })
13764    }
13765
13766    pub fn select_to_end_of_previous_excerpt(
13767        &mut self,
13768        _: &SelectToEndOfPreviousExcerpt,
13769        window: &mut Window,
13770        cx: &mut Context<Self>,
13771    ) {
13772        if matches!(self.mode, EditorMode::SingleLine) {
13773            cx.propagate();
13774            return;
13775        }
13776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13777        self.change_selections(Default::default(), window, cx, |s| {
13778            s.move_heads_with(|map, head, _| {
13779                (
13780                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13781                    SelectionGoal::None,
13782                )
13783            });
13784        })
13785    }
13786
13787    pub fn move_to_beginning(
13788        &mut self,
13789        _: &MoveToBeginning,
13790        window: &mut Window,
13791        cx: &mut Context<Self>,
13792    ) {
13793        if matches!(self.mode, EditorMode::SingleLine) {
13794            cx.propagate();
13795            return;
13796        }
13797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13798        self.change_selections(Default::default(), window, cx, |s| {
13799            s.select_ranges(vec![0..0]);
13800        });
13801    }
13802
13803    pub fn select_to_beginning(
13804        &mut self,
13805        _: &SelectToBeginning,
13806        window: &mut Window,
13807        cx: &mut Context<Self>,
13808    ) {
13809        let mut selection = self.selections.last::<Point>(cx);
13810        selection.set_head(Point::zero(), SelectionGoal::None);
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.select(vec![selection]);
13814        });
13815    }
13816
13817    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13818        if matches!(self.mode, EditorMode::SingleLine) {
13819            cx.propagate();
13820            return;
13821        }
13822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13823        let cursor = self.buffer.read(cx).read(cx).len();
13824        self.change_selections(Default::default(), window, cx, |s| {
13825            s.select_ranges(vec![cursor..cursor])
13826        });
13827    }
13828
13829    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13830        self.nav_history = nav_history;
13831    }
13832
13833    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13834        self.nav_history.as_ref()
13835    }
13836
13837    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13838        self.push_to_nav_history(
13839            self.selections.newest_anchor().head(),
13840            None,
13841            false,
13842            true,
13843            cx,
13844        );
13845    }
13846
13847    fn push_to_nav_history(
13848        &mut self,
13849        cursor_anchor: Anchor,
13850        new_position: Option<Point>,
13851        is_deactivate: bool,
13852        always: bool,
13853        cx: &mut Context<Self>,
13854    ) {
13855        if let Some(nav_history) = self.nav_history.as_mut() {
13856            let buffer = self.buffer.read(cx).read(cx);
13857            let cursor_position = cursor_anchor.to_point(&buffer);
13858            let scroll_state = self.scroll_manager.anchor();
13859            let scroll_top_row = scroll_state.top_row(&buffer);
13860            drop(buffer);
13861
13862            if let Some(new_position) = new_position {
13863                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13864                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13865                    return;
13866                }
13867            }
13868
13869            nav_history.push(
13870                Some(NavigationData {
13871                    cursor_anchor,
13872                    cursor_position,
13873                    scroll_anchor: scroll_state,
13874                    scroll_top_row,
13875                }),
13876                cx,
13877            );
13878            cx.emit(EditorEvent::PushedToNavHistory {
13879                anchor: cursor_anchor,
13880                is_deactivate,
13881            })
13882        }
13883    }
13884
13885    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13887        let buffer = self.buffer.read(cx).snapshot(cx);
13888        let mut selection = self.selections.first::<usize>(cx);
13889        selection.set_head(buffer.len(), SelectionGoal::None);
13890        self.change_selections(Default::default(), window, cx, |s| {
13891            s.select(vec![selection]);
13892        });
13893    }
13894
13895    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13897        let end = self.buffer.read(cx).read(cx).len();
13898        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13899            s.select_ranges(vec![0..end]);
13900        });
13901    }
13902
13903    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13906        let mut selections = self.selections.all::<Point>(cx);
13907        let max_point = display_map.buffer_snapshot.max_point();
13908        for selection in &mut selections {
13909            let rows = selection.spanned_rows(true, &display_map);
13910            selection.start = Point::new(rows.start.0, 0);
13911            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13912            selection.reversed = false;
13913        }
13914        self.change_selections(Default::default(), window, cx, |s| {
13915            s.select(selections);
13916        });
13917    }
13918
13919    pub fn split_selection_into_lines(
13920        &mut self,
13921        action: &SplitSelectionIntoLines,
13922        window: &mut Window,
13923        cx: &mut Context<Self>,
13924    ) {
13925        let selections = self
13926            .selections
13927            .all::<Point>(cx)
13928            .into_iter()
13929            .map(|selection| selection.start..selection.end)
13930            .collect::<Vec<_>>();
13931        self.unfold_ranges(&selections, true, true, cx);
13932
13933        let mut new_selection_ranges = Vec::new();
13934        {
13935            let buffer = self.buffer.read(cx).read(cx);
13936            for selection in selections {
13937                for row in selection.start.row..selection.end.row {
13938                    let line_start = Point::new(row, 0);
13939                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13940
13941                    if action.keep_selections {
13942                        // Keep the selection range for each line
13943                        let selection_start = if row == selection.start.row {
13944                            selection.start
13945                        } else {
13946                            line_start
13947                        };
13948                        new_selection_ranges.push(selection_start..line_end);
13949                    } else {
13950                        // Collapse to cursor at end of line
13951                        new_selection_ranges.push(line_end..line_end);
13952                    }
13953                }
13954
13955                let is_multiline_selection = selection.start.row != selection.end.row;
13956                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13957                // so this action feels more ergonomic when paired with other selection operations
13958                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13959                if !should_skip_last {
13960                    if action.keep_selections {
13961                        if is_multiline_selection {
13962                            let line_start = Point::new(selection.end.row, 0);
13963                            new_selection_ranges.push(line_start..selection.end);
13964                        } else {
13965                            new_selection_ranges.push(selection.start..selection.end);
13966                        }
13967                    } else {
13968                        new_selection_ranges.push(selection.end..selection.end);
13969                    }
13970                }
13971            }
13972        }
13973        self.change_selections(Default::default(), window, cx, |s| {
13974            s.select_ranges(new_selection_ranges);
13975        });
13976    }
13977
13978    pub fn add_selection_above(
13979        &mut self,
13980        _: &AddSelectionAbove,
13981        window: &mut Window,
13982        cx: &mut Context<Self>,
13983    ) {
13984        self.add_selection(true, window, cx);
13985    }
13986
13987    pub fn add_selection_below(
13988        &mut self,
13989        _: &AddSelectionBelow,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        self.add_selection(false, window, cx);
13994    }
13995
13996    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13998
13999        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14000        let all_selections = self.selections.all::<Point>(cx);
14001        let text_layout_details = self.text_layout_details(window);
14002
14003        let (mut columnar_selections, new_selections_to_columnarize) = {
14004            if let Some(state) = self.add_selections_state.as_ref() {
14005                let columnar_selection_ids: HashSet<_> = state
14006                    .groups
14007                    .iter()
14008                    .flat_map(|group| group.stack.iter())
14009                    .copied()
14010                    .collect();
14011
14012                all_selections
14013                    .into_iter()
14014                    .partition(|s| columnar_selection_ids.contains(&s.id))
14015            } else {
14016                (Vec::new(), all_selections)
14017            }
14018        };
14019
14020        let mut state = self
14021            .add_selections_state
14022            .take()
14023            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14024
14025        for selection in new_selections_to_columnarize {
14026            let range = selection.display_range(&display_map).sorted();
14027            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14028            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14029            let positions = start_x.min(end_x)..start_x.max(end_x);
14030            let mut stack = Vec::new();
14031            for row in range.start.row().0..=range.end.row().0 {
14032                if let Some(selection) = self.selections.build_columnar_selection(
14033                    &display_map,
14034                    DisplayRow(row),
14035                    &positions,
14036                    selection.reversed,
14037                    &text_layout_details,
14038                ) {
14039                    stack.push(selection.id);
14040                    columnar_selections.push(selection);
14041                }
14042            }
14043            if !stack.is_empty() {
14044                if above {
14045                    stack.reverse();
14046                }
14047                state.groups.push(AddSelectionsGroup { above, stack });
14048            }
14049        }
14050
14051        let mut final_selections = Vec::new();
14052        let end_row = if above {
14053            DisplayRow(0)
14054        } else {
14055            display_map.max_point().row()
14056        };
14057
14058        let mut last_added_item_per_group = HashMap::default();
14059        for group in state.groups.iter_mut() {
14060            if let Some(last_id) = group.stack.last() {
14061                last_added_item_per_group.insert(*last_id, group);
14062            }
14063        }
14064
14065        for selection in columnar_selections {
14066            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14067                if above == group.above {
14068                    let range = selection.display_range(&display_map).sorted();
14069                    debug_assert_eq!(range.start.row(), range.end.row());
14070                    let mut row = range.start.row();
14071                    let positions =
14072                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14073                            px(start)..px(end)
14074                        } else {
14075                            let start_x =
14076                                display_map.x_for_display_point(range.start, &text_layout_details);
14077                            let end_x =
14078                                display_map.x_for_display_point(range.end, &text_layout_details);
14079                            start_x.min(end_x)..start_x.max(end_x)
14080                        };
14081
14082                    let mut maybe_new_selection = None;
14083                    while row != end_row {
14084                        if above {
14085                            row.0 -= 1;
14086                        } else {
14087                            row.0 += 1;
14088                        }
14089                        if let Some(new_selection) = self.selections.build_columnar_selection(
14090                            &display_map,
14091                            row,
14092                            &positions,
14093                            selection.reversed,
14094                            &text_layout_details,
14095                        ) {
14096                            maybe_new_selection = Some(new_selection);
14097                            break;
14098                        }
14099                    }
14100
14101                    if let Some(new_selection) = maybe_new_selection {
14102                        group.stack.push(new_selection.id);
14103                        if above {
14104                            final_selections.push(new_selection);
14105                            final_selections.push(selection);
14106                        } else {
14107                            final_selections.push(selection);
14108                            final_selections.push(new_selection);
14109                        }
14110                    } else {
14111                        final_selections.push(selection);
14112                    }
14113                } else {
14114                    group.stack.pop();
14115                }
14116            } else {
14117                final_selections.push(selection);
14118            }
14119        }
14120
14121        self.change_selections(Default::default(), window, cx, |s| {
14122            s.select(final_selections);
14123        });
14124
14125        let final_selection_ids: HashSet<_> = self
14126            .selections
14127            .all::<Point>(cx)
14128            .iter()
14129            .map(|s| s.id)
14130            .collect();
14131        state.groups.retain_mut(|group| {
14132            // selections might get merged above so we remove invalid items from stacks
14133            group.stack.retain(|id| final_selection_ids.contains(id));
14134
14135            // single selection in stack can be treated as initial state
14136            group.stack.len() > 1
14137        });
14138
14139        if !state.groups.is_empty() {
14140            self.add_selections_state = Some(state);
14141        }
14142    }
14143
14144    fn select_match_ranges(
14145        &mut self,
14146        range: Range<usize>,
14147        reversed: bool,
14148        replace_newest: bool,
14149        auto_scroll: Option<Autoscroll>,
14150        window: &mut Window,
14151        cx: &mut Context<Editor>,
14152    ) {
14153        self.unfold_ranges(
14154            std::slice::from_ref(&range),
14155            false,
14156            auto_scroll.is_some(),
14157            cx,
14158        );
14159        let effects = if let Some(scroll) = auto_scroll {
14160            SelectionEffects::scroll(scroll)
14161        } else {
14162            SelectionEffects::no_scroll()
14163        };
14164        self.change_selections(effects, window, cx, |s| {
14165            if replace_newest {
14166                s.delete(s.newest_anchor().id);
14167            }
14168            if reversed {
14169                s.insert_range(range.end..range.start);
14170            } else {
14171                s.insert_range(range);
14172            }
14173        });
14174    }
14175
14176    pub fn select_next_match_internal(
14177        &mut self,
14178        display_map: &DisplaySnapshot,
14179        replace_newest: bool,
14180        autoscroll: Option<Autoscroll>,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) -> Result<()> {
14184        let buffer = &display_map.buffer_snapshot;
14185        let mut selections = self.selections.all::<usize>(cx);
14186        if let Some(mut select_next_state) = self.select_next_state.take() {
14187            let query = &select_next_state.query;
14188            if !select_next_state.done {
14189                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14190                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14191                let mut next_selected_range = None;
14192
14193                let bytes_after_last_selection =
14194                    buffer.bytes_in_range(last_selection.end..buffer.len());
14195                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14196                let query_matches = query
14197                    .stream_find_iter(bytes_after_last_selection)
14198                    .map(|result| (last_selection.end, result))
14199                    .chain(
14200                        query
14201                            .stream_find_iter(bytes_before_first_selection)
14202                            .map(|result| (0, result)),
14203                    );
14204
14205                for (start_offset, query_match) in query_matches {
14206                    let query_match = query_match.unwrap(); // can only fail due to I/O
14207                    let offset_range =
14208                        start_offset + query_match.start()..start_offset + query_match.end();
14209
14210                    if !select_next_state.wordwise
14211                        || (!buffer.is_inside_word(offset_range.start, None)
14212                            && !buffer.is_inside_word(offset_range.end, None))
14213                    {
14214                        // TODO: This is n^2, because we might check all the selections
14215                        if !selections
14216                            .iter()
14217                            .any(|selection| selection.range().overlaps(&offset_range))
14218                        {
14219                            next_selected_range = Some(offset_range);
14220                            break;
14221                        }
14222                    }
14223                }
14224
14225                if let Some(next_selected_range) = next_selected_range {
14226                    self.select_match_ranges(
14227                        next_selected_range,
14228                        last_selection.reversed,
14229                        replace_newest,
14230                        autoscroll,
14231                        window,
14232                        cx,
14233                    );
14234                } else {
14235                    select_next_state.done = true;
14236                }
14237            }
14238
14239            self.select_next_state = Some(select_next_state);
14240        } else {
14241            let mut only_carets = true;
14242            let mut same_text_selected = true;
14243            let mut selected_text = None;
14244
14245            let mut selections_iter = selections.iter().peekable();
14246            while let Some(selection) = selections_iter.next() {
14247                if selection.start != selection.end {
14248                    only_carets = false;
14249                }
14250
14251                if same_text_selected {
14252                    if selected_text.is_none() {
14253                        selected_text =
14254                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14255                    }
14256
14257                    if let Some(next_selection) = selections_iter.peek() {
14258                        if next_selection.range().len() == selection.range().len() {
14259                            let next_selected_text = buffer
14260                                .text_for_range(next_selection.range())
14261                                .collect::<String>();
14262                            if Some(next_selected_text) != selected_text {
14263                                same_text_selected = false;
14264                                selected_text = None;
14265                            }
14266                        } else {
14267                            same_text_selected = false;
14268                            selected_text = None;
14269                        }
14270                    }
14271                }
14272            }
14273
14274            if only_carets {
14275                for selection in &mut selections {
14276                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14277                    selection.start = word_range.start;
14278                    selection.end = word_range.end;
14279                    selection.goal = SelectionGoal::None;
14280                    selection.reversed = false;
14281                    self.select_match_ranges(
14282                        selection.start..selection.end,
14283                        selection.reversed,
14284                        replace_newest,
14285                        autoscroll,
14286                        window,
14287                        cx,
14288                    );
14289                }
14290
14291                if selections.len() == 1 {
14292                    let selection = selections
14293                        .last()
14294                        .expect("ensured that there's only one selection");
14295                    let query = buffer
14296                        .text_for_range(selection.start..selection.end)
14297                        .collect::<String>();
14298                    let is_empty = query.is_empty();
14299                    let select_state = SelectNextState {
14300                        query: AhoCorasick::new(&[query])?,
14301                        wordwise: true,
14302                        done: is_empty,
14303                    };
14304                    self.select_next_state = Some(select_state);
14305                } else {
14306                    self.select_next_state = None;
14307                }
14308            } else if let Some(selected_text) = selected_text {
14309                self.select_next_state = Some(SelectNextState {
14310                    query: AhoCorasick::new(&[selected_text])?,
14311                    wordwise: false,
14312                    done: false,
14313                });
14314                self.select_next_match_internal(
14315                    display_map,
14316                    replace_newest,
14317                    autoscroll,
14318                    window,
14319                    cx,
14320                )?;
14321            }
14322        }
14323        Ok(())
14324    }
14325
14326    pub fn select_all_matches(
14327        &mut self,
14328        _action: &SelectAllMatches,
14329        window: &mut Window,
14330        cx: &mut Context<Self>,
14331    ) -> Result<()> {
14332        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14333
14334        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14335
14336        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14337        let Some(select_next_state) = self.select_next_state.as_mut() else {
14338            return Ok(());
14339        };
14340        if select_next_state.done {
14341            return Ok(());
14342        }
14343
14344        let mut new_selections = Vec::new();
14345
14346        let reversed = self.selections.oldest::<usize>(cx).reversed;
14347        let buffer = &display_map.buffer_snapshot;
14348        let query_matches = select_next_state
14349            .query
14350            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14351
14352        for query_match in query_matches.into_iter() {
14353            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14354            let offset_range = if reversed {
14355                query_match.end()..query_match.start()
14356            } else {
14357                query_match.start()..query_match.end()
14358            };
14359
14360            if !select_next_state.wordwise
14361                || (!buffer.is_inside_word(offset_range.start, None)
14362                    && !buffer.is_inside_word(offset_range.end, None))
14363            {
14364                new_selections.push(offset_range.start..offset_range.end);
14365            }
14366        }
14367
14368        select_next_state.done = true;
14369
14370        if new_selections.is_empty() {
14371            log::error!("bug: new_selections is empty in select_all_matches");
14372            return Ok(());
14373        }
14374
14375        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14376        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14377            selections.select_ranges(new_selections)
14378        });
14379
14380        Ok(())
14381    }
14382
14383    pub fn select_next(
14384        &mut self,
14385        action: &SelectNext,
14386        window: &mut Window,
14387        cx: &mut Context<Self>,
14388    ) -> Result<()> {
14389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14391        self.select_next_match_internal(
14392            &display_map,
14393            action.replace_newest,
14394            Some(Autoscroll::newest()),
14395            window,
14396            cx,
14397        )?;
14398        Ok(())
14399    }
14400
14401    pub fn select_previous(
14402        &mut self,
14403        action: &SelectPrevious,
14404        window: &mut Window,
14405        cx: &mut Context<Self>,
14406    ) -> Result<()> {
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14409        let buffer = &display_map.buffer_snapshot;
14410        let mut selections = self.selections.all::<usize>(cx);
14411        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14412            let query = &select_prev_state.query;
14413            if !select_prev_state.done {
14414                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14415                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14416                let mut next_selected_range = None;
14417                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14418                let bytes_before_last_selection =
14419                    buffer.reversed_bytes_in_range(0..last_selection.start);
14420                let bytes_after_first_selection =
14421                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14422                let query_matches = query
14423                    .stream_find_iter(bytes_before_last_selection)
14424                    .map(|result| (last_selection.start, result))
14425                    .chain(
14426                        query
14427                            .stream_find_iter(bytes_after_first_selection)
14428                            .map(|result| (buffer.len(), result)),
14429                    );
14430                for (end_offset, query_match) in query_matches {
14431                    let query_match = query_match.unwrap(); // can only fail due to I/O
14432                    let offset_range =
14433                        end_offset - query_match.end()..end_offset - query_match.start();
14434
14435                    if !select_prev_state.wordwise
14436                        || (!buffer.is_inside_word(offset_range.start, None)
14437                            && !buffer.is_inside_word(offset_range.end, None))
14438                    {
14439                        next_selected_range = Some(offset_range);
14440                        break;
14441                    }
14442                }
14443
14444                if let Some(next_selected_range) = next_selected_range {
14445                    self.select_match_ranges(
14446                        next_selected_range,
14447                        last_selection.reversed,
14448                        action.replace_newest,
14449                        Some(Autoscroll::newest()),
14450                        window,
14451                        cx,
14452                    );
14453                } else {
14454                    select_prev_state.done = true;
14455                }
14456            }
14457
14458            self.select_prev_state = Some(select_prev_state);
14459        } else {
14460            let mut only_carets = true;
14461            let mut same_text_selected = true;
14462            let mut selected_text = None;
14463
14464            let mut selections_iter = selections.iter().peekable();
14465            while let Some(selection) = selections_iter.next() {
14466                if selection.start != selection.end {
14467                    only_carets = false;
14468                }
14469
14470                if same_text_selected {
14471                    if selected_text.is_none() {
14472                        selected_text =
14473                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14474                    }
14475
14476                    if let Some(next_selection) = selections_iter.peek() {
14477                        if next_selection.range().len() == selection.range().len() {
14478                            let next_selected_text = buffer
14479                                .text_for_range(next_selection.range())
14480                                .collect::<String>();
14481                            if Some(next_selected_text) != selected_text {
14482                                same_text_selected = false;
14483                                selected_text = None;
14484                            }
14485                        } else {
14486                            same_text_selected = false;
14487                            selected_text = None;
14488                        }
14489                    }
14490                }
14491            }
14492
14493            if only_carets {
14494                for selection in &mut selections {
14495                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14496                    selection.start = word_range.start;
14497                    selection.end = word_range.end;
14498                    selection.goal = SelectionGoal::None;
14499                    selection.reversed = false;
14500                    self.select_match_ranges(
14501                        selection.start..selection.end,
14502                        selection.reversed,
14503                        action.replace_newest,
14504                        Some(Autoscroll::newest()),
14505                        window,
14506                        cx,
14507                    );
14508                }
14509                if selections.len() == 1 {
14510                    let selection = selections
14511                        .last()
14512                        .expect("ensured that there's only one selection");
14513                    let query = buffer
14514                        .text_for_range(selection.start..selection.end)
14515                        .collect::<String>();
14516                    let is_empty = query.is_empty();
14517                    let select_state = SelectNextState {
14518                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14519                        wordwise: true,
14520                        done: is_empty,
14521                    };
14522                    self.select_prev_state = Some(select_state);
14523                } else {
14524                    self.select_prev_state = None;
14525                }
14526            } else if let Some(selected_text) = selected_text {
14527                self.select_prev_state = Some(SelectNextState {
14528                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14529                    wordwise: false,
14530                    done: false,
14531                });
14532                self.select_previous(action, window, cx)?;
14533            }
14534        }
14535        Ok(())
14536    }
14537
14538    pub fn find_next_match(
14539        &mut self,
14540        _: &FindNextMatch,
14541        window: &mut Window,
14542        cx: &mut Context<Self>,
14543    ) -> Result<()> {
14544        let selections = self.selections.disjoint_anchors_arc();
14545        match selections.first() {
14546            Some(first) if selections.len() >= 2 => {
14547                self.change_selections(Default::default(), window, cx, |s| {
14548                    s.select_ranges([first.range()]);
14549                });
14550            }
14551            _ => self.select_next(
14552                &SelectNext {
14553                    replace_newest: true,
14554                },
14555                window,
14556                cx,
14557            )?,
14558        }
14559        Ok(())
14560    }
14561
14562    pub fn find_previous_match(
14563        &mut self,
14564        _: &FindPreviousMatch,
14565        window: &mut Window,
14566        cx: &mut Context<Self>,
14567    ) -> Result<()> {
14568        let selections = self.selections.disjoint_anchors_arc();
14569        match selections.last() {
14570            Some(last) if selections.len() >= 2 => {
14571                self.change_selections(Default::default(), window, cx, |s| {
14572                    s.select_ranges([last.range()]);
14573                });
14574            }
14575            _ => self.select_previous(
14576                &SelectPrevious {
14577                    replace_newest: true,
14578                },
14579                window,
14580                cx,
14581            )?,
14582        }
14583        Ok(())
14584    }
14585
14586    pub fn toggle_comments(
14587        &mut self,
14588        action: &ToggleComments,
14589        window: &mut Window,
14590        cx: &mut Context<Self>,
14591    ) {
14592        if self.read_only(cx) {
14593            return;
14594        }
14595        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14596        let text_layout_details = &self.text_layout_details(window);
14597        self.transact(window, cx, |this, window, cx| {
14598            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14599            let mut edits = Vec::new();
14600            let mut selection_edit_ranges = Vec::new();
14601            let mut last_toggled_row = None;
14602            let snapshot = this.buffer.read(cx).read(cx);
14603            let empty_str: Arc<str> = Arc::default();
14604            let mut suffixes_inserted = Vec::new();
14605            let ignore_indent = action.ignore_indent;
14606
14607            fn comment_prefix_range(
14608                snapshot: &MultiBufferSnapshot,
14609                row: MultiBufferRow,
14610                comment_prefix: &str,
14611                comment_prefix_whitespace: &str,
14612                ignore_indent: bool,
14613            ) -> Range<Point> {
14614                let indent_size = if ignore_indent {
14615                    0
14616                } else {
14617                    snapshot.indent_size_for_line(row).len
14618                };
14619
14620                let start = Point::new(row.0, indent_size);
14621
14622                let mut line_bytes = snapshot
14623                    .bytes_in_range(start..snapshot.max_point())
14624                    .flatten()
14625                    .copied();
14626
14627                // If this line currently begins with the line comment prefix, then record
14628                // the range containing the prefix.
14629                if line_bytes
14630                    .by_ref()
14631                    .take(comment_prefix.len())
14632                    .eq(comment_prefix.bytes())
14633                {
14634                    // Include any whitespace that matches the comment prefix.
14635                    let matching_whitespace_len = line_bytes
14636                        .zip(comment_prefix_whitespace.bytes())
14637                        .take_while(|(a, b)| a == b)
14638                        .count() as u32;
14639                    let end = Point::new(
14640                        start.row,
14641                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14642                    );
14643                    start..end
14644                } else {
14645                    start..start
14646                }
14647            }
14648
14649            fn comment_suffix_range(
14650                snapshot: &MultiBufferSnapshot,
14651                row: MultiBufferRow,
14652                comment_suffix: &str,
14653                comment_suffix_has_leading_space: bool,
14654            ) -> Range<Point> {
14655                let end = Point::new(row.0, snapshot.line_len(row));
14656                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14657
14658                let mut line_end_bytes = snapshot
14659                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14660                    .flatten()
14661                    .copied();
14662
14663                let leading_space_len = if suffix_start_column > 0
14664                    && line_end_bytes.next() == Some(b' ')
14665                    && comment_suffix_has_leading_space
14666                {
14667                    1
14668                } else {
14669                    0
14670                };
14671
14672                // If this line currently begins with the line comment prefix, then record
14673                // the range containing the prefix.
14674                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14675                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14676                    start..end
14677                } else {
14678                    end..end
14679                }
14680            }
14681
14682            // TODO: Handle selections that cross excerpts
14683            for selection in &mut selections {
14684                let start_column = snapshot
14685                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14686                    .len;
14687                let language = if let Some(language) =
14688                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14689                {
14690                    language
14691                } else {
14692                    continue;
14693                };
14694
14695                selection_edit_ranges.clear();
14696
14697                // If multiple selections contain a given row, avoid processing that
14698                // row more than once.
14699                let mut start_row = MultiBufferRow(selection.start.row);
14700                if last_toggled_row == Some(start_row) {
14701                    start_row = start_row.next_row();
14702                }
14703                let end_row =
14704                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14705                        MultiBufferRow(selection.end.row - 1)
14706                    } else {
14707                        MultiBufferRow(selection.end.row)
14708                    };
14709                last_toggled_row = Some(end_row);
14710
14711                if start_row > end_row {
14712                    continue;
14713                }
14714
14715                // If the language has line comments, toggle those.
14716                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14717
14718                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14719                if ignore_indent {
14720                    full_comment_prefixes = full_comment_prefixes
14721                        .into_iter()
14722                        .map(|s| Arc::from(s.trim_end()))
14723                        .collect();
14724                }
14725
14726                if !full_comment_prefixes.is_empty() {
14727                    let first_prefix = full_comment_prefixes
14728                        .first()
14729                        .expect("prefixes is non-empty");
14730                    let prefix_trimmed_lengths = full_comment_prefixes
14731                        .iter()
14732                        .map(|p| p.trim_end_matches(' ').len())
14733                        .collect::<SmallVec<[usize; 4]>>();
14734
14735                    let mut all_selection_lines_are_comments = true;
14736
14737                    for row in start_row.0..=end_row.0 {
14738                        let row = MultiBufferRow(row);
14739                        if start_row < end_row && snapshot.is_line_blank(row) {
14740                            continue;
14741                        }
14742
14743                        let prefix_range = full_comment_prefixes
14744                            .iter()
14745                            .zip(prefix_trimmed_lengths.iter().copied())
14746                            .map(|(prefix, trimmed_prefix_len)| {
14747                                comment_prefix_range(
14748                                    snapshot.deref(),
14749                                    row,
14750                                    &prefix[..trimmed_prefix_len],
14751                                    &prefix[trimmed_prefix_len..],
14752                                    ignore_indent,
14753                                )
14754                            })
14755                            .max_by_key(|range| range.end.column - range.start.column)
14756                            .expect("prefixes is non-empty");
14757
14758                        if prefix_range.is_empty() {
14759                            all_selection_lines_are_comments = false;
14760                        }
14761
14762                        selection_edit_ranges.push(prefix_range);
14763                    }
14764
14765                    if all_selection_lines_are_comments {
14766                        edits.extend(
14767                            selection_edit_ranges
14768                                .iter()
14769                                .cloned()
14770                                .map(|range| (range, empty_str.clone())),
14771                        );
14772                    } else {
14773                        let min_column = selection_edit_ranges
14774                            .iter()
14775                            .map(|range| range.start.column)
14776                            .min()
14777                            .unwrap_or(0);
14778                        edits.extend(selection_edit_ranges.iter().map(|range| {
14779                            let position = Point::new(range.start.row, min_column);
14780                            (position..position, first_prefix.clone())
14781                        }));
14782                    }
14783                } else if let Some(BlockCommentConfig {
14784                    start: full_comment_prefix,
14785                    end: comment_suffix,
14786                    ..
14787                }) = language.block_comment()
14788                {
14789                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14790                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14791                    let prefix_range = comment_prefix_range(
14792                        snapshot.deref(),
14793                        start_row,
14794                        comment_prefix,
14795                        comment_prefix_whitespace,
14796                        ignore_indent,
14797                    );
14798                    let suffix_range = comment_suffix_range(
14799                        snapshot.deref(),
14800                        end_row,
14801                        comment_suffix.trim_start_matches(' '),
14802                        comment_suffix.starts_with(' '),
14803                    );
14804
14805                    if prefix_range.is_empty() || suffix_range.is_empty() {
14806                        edits.push((
14807                            prefix_range.start..prefix_range.start,
14808                            full_comment_prefix.clone(),
14809                        ));
14810                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14811                        suffixes_inserted.push((end_row, comment_suffix.len()));
14812                    } else {
14813                        edits.push((prefix_range, empty_str.clone()));
14814                        edits.push((suffix_range, empty_str.clone()));
14815                    }
14816                } else {
14817                    continue;
14818                }
14819            }
14820
14821            drop(snapshot);
14822            this.buffer.update(cx, |buffer, cx| {
14823                buffer.edit(edits, None, cx);
14824            });
14825
14826            // Adjust selections so that they end before any comment suffixes that
14827            // were inserted.
14828            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14829            let mut selections = this.selections.all::<Point>(cx);
14830            let snapshot = this.buffer.read(cx).read(cx);
14831            for selection in &mut selections {
14832                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14833                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14834                        Ordering::Less => {
14835                            suffixes_inserted.next();
14836                            continue;
14837                        }
14838                        Ordering::Greater => break,
14839                        Ordering::Equal => {
14840                            if selection.end.column == snapshot.line_len(row) {
14841                                if selection.is_empty() {
14842                                    selection.start.column -= suffix_len as u32;
14843                                }
14844                                selection.end.column -= suffix_len as u32;
14845                            }
14846                            break;
14847                        }
14848                    }
14849                }
14850            }
14851
14852            drop(snapshot);
14853            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14854
14855            let selections = this.selections.all::<Point>(cx);
14856            let selections_on_single_row = selections.windows(2).all(|selections| {
14857                selections[0].start.row == selections[1].start.row
14858                    && selections[0].end.row == selections[1].end.row
14859                    && selections[0].start.row == selections[0].end.row
14860            });
14861            let selections_selecting = selections
14862                .iter()
14863                .any(|selection| selection.start != selection.end);
14864            let advance_downwards = action.advance_downwards
14865                && selections_on_single_row
14866                && !selections_selecting
14867                && !matches!(this.mode, EditorMode::SingleLine);
14868
14869            if advance_downwards {
14870                let snapshot = this.buffer.read(cx).snapshot(cx);
14871
14872                this.change_selections(Default::default(), window, cx, |s| {
14873                    s.move_cursors_with(|display_snapshot, display_point, _| {
14874                        let mut point = display_point.to_point(display_snapshot);
14875                        point.row += 1;
14876                        point = snapshot.clip_point(point, Bias::Left);
14877                        let display_point = point.to_display_point(display_snapshot);
14878                        let goal = SelectionGoal::HorizontalPosition(
14879                            display_snapshot
14880                                .x_for_display_point(display_point, text_layout_details)
14881                                .into(),
14882                        );
14883                        (display_point, goal)
14884                    })
14885                });
14886            }
14887        });
14888    }
14889
14890    pub fn select_enclosing_symbol(
14891        &mut self,
14892        _: &SelectEnclosingSymbol,
14893        window: &mut Window,
14894        cx: &mut Context<Self>,
14895    ) {
14896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14897
14898        let buffer = self.buffer.read(cx).snapshot(cx);
14899        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14900
14901        fn update_selection(
14902            selection: &Selection<usize>,
14903            buffer_snap: &MultiBufferSnapshot,
14904        ) -> Option<Selection<usize>> {
14905            let cursor = selection.head();
14906            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14907            for symbol in symbols.iter().rev() {
14908                let start = symbol.range.start.to_offset(buffer_snap);
14909                let end = symbol.range.end.to_offset(buffer_snap);
14910                let new_range = start..end;
14911                if start < selection.start || end > selection.end {
14912                    return Some(Selection {
14913                        id: selection.id,
14914                        start: new_range.start,
14915                        end: new_range.end,
14916                        goal: SelectionGoal::None,
14917                        reversed: selection.reversed,
14918                    });
14919                }
14920            }
14921            None
14922        }
14923
14924        let mut selected_larger_symbol = false;
14925        let new_selections = old_selections
14926            .iter()
14927            .map(|selection| match update_selection(selection, &buffer) {
14928                Some(new_selection) => {
14929                    if new_selection.range() != selection.range() {
14930                        selected_larger_symbol = true;
14931                    }
14932                    new_selection
14933                }
14934                None => selection.clone(),
14935            })
14936            .collect::<Vec<_>>();
14937
14938        if selected_larger_symbol {
14939            self.change_selections(Default::default(), window, cx, |s| {
14940                s.select(new_selections);
14941            });
14942        }
14943    }
14944
14945    pub fn select_larger_syntax_node(
14946        &mut self,
14947        _: &SelectLargerSyntaxNode,
14948        window: &mut Window,
14949        cx: &mut Context<Self>,
14950    ) {
14951        let Some(visible_row_count) = self.visible_row_count() else {
14952            return;
14953        };
14954        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14955        if old_selections.is_empty() {
14956            return;
14957        }
14958
14959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14960
14961        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14962        let buffer = self.buffer.read(cx).snapshot(cx);
14963
14964        let mut selected_larger_node = false;
14965        let mut new_selections = old_selections
14966            .iter()
14967            .map(|selection| {
14968                let old_range = selection.start..selection.end;
14969
14970                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14971                    // manually select word at selection
14972                    if ["string_content", "inline"].contains(&node.kind()) {
14973                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
14974                        // ignore if word is already selected
14975                        if !word_range.is_empty() && old_range != word_range {
14976                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
14977                            // only select word if start and end point belongs to same word
14978                            if word_range == last_word_range {
14979                                selected_larger_node = true;
14980                                return Selection {
14981                                    id: selection.id,
14982                                    start: word_range.start,
14983                                    end: word_range.end,
14984                                    goal: SelectionGoal::None,
14985                                    reversed: selection.reversed,
14986                                };
14987                            }
14988                        }
14989                    }
14990                }
14991
14992                let mut new_range = old_range.clone();
14993                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14994                {
14995                    new_range = match containing_range {
14996                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14997                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14998                    };
14999                    if !node.is_named() {
15000                        continue;
15001                    }
15002                    if !display_map.intersects_fold(new_range.start)
15003                        && !display_map.intersects_fold(new_range.end)
15004                    {
15005                        break;
15006                    }
15007                }
15008
15009                selected_larger_node |= new_range != old_range;
15010                Selection {
15011                    id: selection.id,
15012                    start: new_range.start,
15013                    end: new_range.end,
15014                    goal: SelectionGoal::None,
15015                    reversed: selection.reversed,
15016                }
15017            })
15018            .collect::<Vec<_>>();
15019
15020        if !selected_larger_node {
15021            return; // don't put this call in the history
15022        }
15023
15024        // scroll based on transformation done to the last selection created by the user
15025        let (last_old, last_new) = old_selections
15026            .last()
15027            .zip(new_selections.last().cloned())
15028            .expect("old_selections isn't empty");
15029
15030        // revert selection
15031        let is_selection_reversed = {
15032            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15033            new_selections.last_mut().expect("checked above").reversed =
15034                should_newest_selection_be_reversed;
15035            should_newest_selection_be_reversed
15036        };
15037
15038        if selected_larger_node {
15039            self.select_syntax_node_history.disable_clearing = true;
15040            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15041                s.select(new_selections.clone());
15042            });
15043            self.select_syntax_node_history.disable_clearing = false;
15044        }
15045
15046        let start_row = last_new.start.to_display_point(&display_map).row().0;
15047        let end_row = last_new.end.to_display_point(&display_map).row().0;
15048        let selection_height = end_row - start_row + 1;
15049        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15050
15051        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15052        let scroll_behavior = if fits_on_the_screen {
15053            self.request_autoscroll(Autoscroll::fit(), cx);
15054            SelectSyntaxNodeScrollBehavior::FitSelection
15055        } else if is_selection_reversed {
15056            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15057            SelectSyntaxNodeScrollBehavior::CursorTop
15058        } else {
15059            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15060            SelectSyntaxNodeScrollBehavior::CursorBottom
15061        };
15062
15063        self.select_syntax_node_history.push((
15064            old_selections,
15065            scroll_behavior,
15066            is_selection_reversed,
15067        ));
15068    }
15069
15070    pub fn select_smaller_syntax_node(
15071        &mut self,
15072        _: &SelectSmallerSyntaxNode,
15073        window: &mut Window,
15074        cx: &mut Context<Self>,
15075    ) {
15076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15077
15078        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15079            self.select_syntax_node_history.pop()
15080        {
15081            if let Some(selection) = selections.last_mut() {
15082                selection.reversed = is_selection_reversed;
15083            }
15084
15085            self.select_syntax_node_history.disable_clearing = true;
15086            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15087                s.select(selections.to_vec());
15088            });
15089            self.select_syntax_node_history.disable_clearing = false;
15090
15091            match scroll_behavior {
15092                SelectSyntaxNodeScrollBehavior::CursorTop => {
15093                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15094                }
15095                SelectSyntaxNodeScrollBehavior::FitSelection => {
15096                    self.request_autoscroll(Autoscroll::fit(), cx);
15097                }
15098                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15099                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15100                }
15101            }
15102        }
15103    }
15104
15105    pub fn unwrap_syntax_node(
15106        &mut self,
15107        _: &UnwrapSyntaxNode,
15108        window: &mut Window,
15109        cx: &mut Context<Self>,
15110    ) {
15111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15112
15113        let buffer = self.buffer.read(cx).snapshot(cx);
15114        let selections = self
15115            .selections
15116            .all::<usize>(cx)
15117            .into_iter()
15118            // subtracting the offset requires sorting
15119            .sorted_by_key(|i| i.start);
15120
15121        let full_edits = selections
15122            .into_iter()
15123            .filter_map(|selection| {
15124                let child = if selection.is_empty()
15125                    && let Some((_, ancestor_range)) =
15126                        buffer.syntax_ancestor(selection.start..selection.end)
15127                {
15128                    match ancestor_range {
15129                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15130                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15131                    }
15132                } else {
15133                    selection.range()
15134                };
15135
15136                let mut parent = child.clone();
15137                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15138                    parent = match ancestor_range {
15139                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15140                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15141                    };
15142                    if parent.start < child.start || parent.end > child.end {
15143                        break;
15144                    }
15145                }
15146
15147                if parent == child {
15148                    return None;
15149                }
15150                let text = buffer.text_for_range(child).collect::<String>();
15151                Some((selection.id, parent, text))
15152            })
15153            .collect::<Vec<_>>();
15154        if full_edits.is_empty() {
15155            return;
15156        }
15157
15158        self.transact(window, cx, |this, window, cx| {
15159            this.buffer.update(cx, |buffer, cx| {
15160                buffer.edit(
15161                    full_edits
15162                        .iter()
15163                        .map(|(_, p, t)| (p.clone(), t.clone()))
15164                        .collect::<Vec<_>>(),
15165                    None,
15166                    cx,
15167                );
15168            });
15169            this.change_selections(Default::default(), window, cx, |s| {
15170                let mut offset = 0;
15171                let mut selections = vec![];
15172                for (id, parent, text) in full_edits {
15173                    let start = parent.start - offset;
15174                    offset += parent.len() - text.len();
15175                    selections.push(Selection {
15176                        id,
15177                        start,
15178                        end: start + text.len(),
15179                        reversed: false,
15180                        goal: Default::default(),
15181                    });
15182                }
15183                s.select(selections);
15184            });
15185        });
15186    }
15187
15188    pub fn select_next_syntax_node(
15189        &mut self,
15190        _: &SelectNextSyntaxNode,
15191        window: &mut Window,
15192        cx: &mut Context<Self>,
15193    ) {
15194        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15195        if old_selections.is_empty() {
15196            return;
15197        }
15198
15199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15200
15201        let buffer = self.buffer.read(cx).snapshot(cx);
15202        let mut selected_sibling = false;
15203
15204        let new_selections = old_selections
15205            .iter()
15206            .map(|selection| {
15207                let old_range = selection.start..selection.end;
15208
15209                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15210                    let new_range = node.byte_range();
15211                    selected_sibling = true;
15212                    Selection {
15213                        id: selection.id,
15214                        start: new_range.start,
15215                        end: new_range.end,
15216                        goal: SelectionGoal::None,
15217                        reversed: selection.reversed,
15218                    }
15219                } else {
15220                    selection.clone()
15221                }
15222            })
15223            .collect::<Vec<_>>();
15224
15225        if selected_sibling {
15226            self.change_selections(
15227                SelectionEffects::scroll(Autoscroll::fit()),
15228                window,
15229                cx,
15230                |s| {
15231                    s.select(new_selections);
15232                },
15233            );
15234        }
15235    }
15236
15237    pub fn select_prev_syntax_node(
15238        &mut self,
15239        _: &SelectPreviousSyntaxNode,
15240        window: &mut Window,
15241        cx: &mut Context<Self>,
15242    ) {
15243        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15244        if old_selections.is_empty() {
15245            return;
15246        }
15247
15248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15249
15250        let buffer = self.buffer.read(cx).snapshot(cx);
15251        let mut selected_sibling = false;
15252
15253        let new_selections = old_selections
15254            .iter()
15255            .map(|selection| {
15256                let old_range = selection.start..selection.end;
15257
15258                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15259                    let new_range = node.byte_range();
15260                    selected_sibling = true;
15261                    Selection {
15262                        id: selection.id,
15263                        start: new_range.start,
15264                        end: new_range.end,
15265                        goal: SelectionGoal::None,
15266                        reversed: selection.reversed,
15267                    }
15268                } else {
15269                    selection.clone()
15270                }
15271            })
15272            .collect::<Vec<_>>();
15273
15274        if selected_sibling {
15275            self.change_selections(
15276                SelectionEffects::scroll(Autoscroll::fit()),
15277                window,
15278                cx,
15279                |s| {
15280                    s.select(new_selections);
15281                },
15282            );
15283        }
15284    }
15285
15286    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15287        if !EditorSettings::get_global(cx).gutter.runnables {
15288            self.clear_tasks();
15289            return Task::ready(());
15290        }
15291        let project = self.project().map(Entity::downgrade);
15292        let task_sources = self.lsp_task_sources(cx);
15293        let multi_buffer = self.buffer.downgrade();
15294        cx.spawn_in(window, async move |editor, cx| {
15295            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15296            let Some(project) = project.and_then(|p| p.upgrade()) else {
15297                return;
15298            };
15299            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15300                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15301            }) else {
15302                return;
15303            };
15304
15305            let hide_runnables = project
15306                .update(cx, |project, _| project.is_via_collab())
15307                .unwrap_or(true);
15308            if hide_runnables {
15309                return;
15310            }
15311            let new_rows =
15312                cx.background_spawn({
15313                    let snapshot = display_snapshot.clone();
15314                    async move {
15315                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15316                    }
15317                })
15318                    .await;
15319            let Ok(lsp_tasks) =
15320                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15321            else {
15322                return;
15323            };
15324            let lsp_tasks = lsp_tasks.await;
15325
15326            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15327                lsp_tasks
15328                    .into_iter()
15329                    .flat_map(|(kind, tasks)| {
15330                        tasks.into_iter().filter_map(move |(location, task)| {
15331                            Some((kind.clone(), location?, task))
15332                        })
15333                    })
15334                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15335                        let buffer = location.target.buffer;
15336                        let buffer_snapshot = buffer.read(cx).snapshot();
15337                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15338                            |(excerpt_id, snapshot, _)| {
15339                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15340                                    display_snapshot
15341                                        .buffer_snapshot
15342                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15343                                } else {
15344                                    None
15345                                }
15346                            },
15347                        );
15348                        if let Some(offset) = offset {
15349                            let task_buffer_range =
15350                                location.target.range.to_point(&buffer_snapshot);
15351                            let context_buffer_range =
15352                                task_buffer_range.to_offset(&buffer_snapshot);
15353                            let context_range = BufferOffset(context_buffer_range.start)
15354                                ..BufferOffset(context_buffer_range.end);
15355
15356                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15357                                .or_insert_with(|| RunnableTasks {
15358                                    templates: Vec::new(),
15359                                    offset,
15360                                    column: task_buffer_range.start.column,
15361                                    extra_variables: HashMap::default(),
15362                                    context_range,
15363                                })
15364                                .templates
15365                                .push((kind, task.original_task().clone()));
15366                        }
15367
15368                        acc
15369                    })
15370            }) else {
15371                return;
15372            };
15373
15374            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15375                buffer.language_settings(cx).tasks.prefer_lsp
15376            }) else {
15377                return;
15378            };
15379
15380            let rows = Self::runnable_rows(
15381                project,
15382                display_snapshot,
15383                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15384                new_rows,
15385                cx.clone(),
15386            )
15387            .await;
15388            editor
15389                .update(cx, |editor, _| {
15390                    editor.clear_tasks();
15391                    for (key, mut value) in rows {
15392                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15393                            value.templates.extend(lsp_tasks.templates);
15394                        }
15395
15396                        editor.insert_tasks(key, value);
15397                    }
15398                    for (key, value) in lsp_tasks_by_rows {
15399                        editor.insert_tasks(key, value);
15400                    }
15401                })
15402                .ok();
15403        })
15404    }
15405    fn fetch_runnable_ranges(
15406        snapshot: &DisplaySnapshot,
15407        range: Range<Anchor>,
15408    ) -> Vec<language::RunnableRange> {
15409        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15410    }
15411
15412    fn runnable_rows(
15413        project: Entity<Project>,
15414        snapshot: DisplaySnapshot,
15415        prefer_lsp: bool,
15416        runnable_ranges: Vec<RunnableRange>,
15417        cx: AsyncWindowContext,
15418    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15419        cx.spawn(async move |cx| {
15420            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15421            for mut runnable in runnable_ranges {
15422                let Some(tasks) = cx
15423                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15424                    .ok()
15425                else {
15426                    continue;
15427                };
15428                let mut tasks = tasks.await;
15429
15430                if prefer_lsp {
15431                    tasks.retain(|(task_kind, _)| {
15432                        !matches!(task_kind, TaskSourceKind::Language { .. })
15433                    });
15434                }
15435                if tasks.is_empty() {
15436                    continue;
15437                }
15438
15439                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15440                let Some(row) = snapshot
15441                    .buffer_snapshot
15442                    .buffer_line_for_row(MultiBufferRow(point.row))
15443                    .map(|(_, range)| range.start.row)
15444                else {
15445                    continue;
15446                };
15447
15448                let context_range =
15449                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15450                runnable_rows.push((
15451                    (runnable.buffer_id, row),
15452                    RunnableTasks {
15453                        templates: tasks,
15454                        offset: snapshot
15455                            .buffer_snapshot
15456                            .anchor_before(runnable.run_range.start),
15457                        context_range,
15458                        column: point.column,
15459                        extra_variables: runnable.extra_captures,
15460                    },
15461                ));
15462            }
15463            runnable_rows
15464        })
15465    }
15466
15467    fn templates_with_tags(
15468        project: &Entity<Project>,
15469        runnable: &mut Runnable,
15470        cx: &mut App,
15471    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15472        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15473            let (worktree_id, file) = project
15474                .buffer_for_id(runnable.buffer, cx)
15475                .and_then(|buffer| buffer.read(cx).file())
15476                .map(|file| (file.worktree_id(cx), file.clone()))
15477                .unzip();
15478
15479            (
15480                project.task_store().read(cx).task_inventory().cloned(),
15481                worktree_id,
15482                file,
15483            )
15484        });
15485
15486        let tags = mem::take(&mut runnable.tags);
15487        let language = runnable.language.clone();
15488        cx.spawn(async move |cx| {
15489            let mut templates_with_tags = Vec::new();
15490            if let Some(inventory) = inventory {
15491                for RunnableTag(tag) in tags {
15492                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15493                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15494                    }) else {
15495                        return templates_with_tags;
15496                    };
15497                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15498                        move |(_, template)| {
15499                            template.tags.iter().any(|source_tag| source_tag == &tag)
15500                        },
15501                    ));
15502                }
15503            }
15504            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15505
15506            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15507                // Strongest source wins; if we have worktree tag binding, prefer that to
15508                // global and language bindings;
15509                // if we have a global binding, prefer that to language binding.
15510                let first_mismatch = templates_with_tags
15511                    .iter()
15512                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15513                if let Some(index) = first_mismatch {
15514                    templates_with_tags.truncate(index);
15515                }
15516            }
15517
15518            templates_with_tags
15519        })
15520    }
15521
15522    pub fn move_to_enclosing_bracket(
15523        &mut self,
15524        _: &MoveToEnclosingBracket,
15525        window: &mut Window,
15526        cx: &mut Context<Self>,
15527    ) {
15528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15529        self.change_selections(Default::default(), window, cx, |s| {
15530            s.move_offsets_with(|snapshot, selection| {
15531                let Some(enclosing_bracket_ranges) =
15532                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15533                else {
15534                    return;
15535                };
15536
15537                let mut best_length = usize::MAX;
15538                let mut best_inside = false;
15539                let mut best_in_bracket_range = false;
15540                let mut best_destination = None;
15541                for (open, close) in enclosing_bracket_ranges {
15542                    let close = close.to_inclusive();
15543                    let length = close.end() - open.start;
15544                    let inside = selection.start >= open.end && selection.end <= *close.start();
15545                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15546                        || close.contains(&selection.head());
15547
15548                    // If best is next to a bracket and current isn't, skip
15549                    if !in_bracket_range && best_in_bracket_range {
15550                        continue;
15551                    }
15552
15553                    // Prefer smaller lengths unless best is inside and current isn't
15554                    if length > best_length && (best_inside || !inside) {
15555                        continue;
15556                    }
15557
15558                    best_length = length;
15559                    best_inside = inside;
15560                    best_in_bracket_range = in_bracket_range;
15561                    best_destination = Some(
15562                        if close.contains(&selection.start) && close.contains(&selection.end) {
15563                            if inside { open.end } else { open.start }
15564                        } else if inside {
15565                            *close.start()
15566                        } else {
15567                            *close.end()
15568                        },
15569                    );
15570                }
15571
15572                if let Some(destination) = best_destination {
15573                    selection.collapse_to(destination, SelectionGoal::None);
15574                }
15575            })
15576        });
15577    }
15578
15579    pub fn undo_selection(
15580        &mut self,
15581        _: &UndoSelection,
15582        window: &mut Window,
15583        cx: &mut Context<Self>,
15584    ) {
15585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15586        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15587            self.selection_history.mode = SelectionHistoryMode::Undoing;
15588            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15589                this.end_selection(window, cx);
15590                this.change_selections(
15591                    SelectionEffects::scroll(Autoscroll::newest()),
15592                    window,
15593                    cx,
15594                    |s| s.select_anchors(entry.selections.to_vec()),
15595                );
15596            });
15597            self.selection_history.mode = SelectionHistoryMode::Normal;
15598
15599            self.select_next_state = entry.select_next_state;
15600            self.select_prev_state = entry.select_prev_state;
15601            self.add_selections_state = entry.add_selections_state;
15602        }
15603    }
15604
15605    pub fn redo_selection(
15606        &mut self,
15607        _: &RedoSelection,
15608        window: &mut Window,
15609        cx: &mut Context<Self>,
15610    ) {
15611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15612        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15613            self.selection_history.mode = SelectionHistoryMode::Redoing;
15614            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15615                this.end_selection(window, cx);
15616                this.change_selections(
15617                    SelectionEffects::scroll(Autoscroll::newest()),
15618                    window,
15619                    cx,
15620                    |s| s.select_anchors(entry.selections.to_vec()),
15621                );
15622            });
15623            self.selection_history.mode = SelectionHistoryMode::Normal;
15624
15625            self.select_next_state = entry.select_next_state;
15626            self.select_prev_state = entry.select_prev_state;
15627            self.add_selections_state = entry.add_selections_state;
15628        }
15629    }
15630
15631    pub fn expand_excerpts(
15632        &mut self,
15633        action: &ExpandExcerpts,
15634        _: &mut Window,
15635        cx: &mut Context<Self>,
15636    ) {
15637        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15638    }
15639
15640    pub fn expand_excerpts_down(
15641        &mut self,
15642        action: &ExpandExcerptsDown,
15643        _: &mut Window,
15644        cx: &mut Context<Self>,
15645    ) {
15646        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15647    }
15648
15649    pub fn expand_excerpts_up(
15650        &mut self,
15651        action: &ExpandExcerptsUp,
15652        _: &mut Window,
15653        cx: &mut Context<Self>,
15654    ) {
15655        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15656    }
15657
15658    pub fn expand_excerpts_for_direction(
15659        &mut self,
15660        lines: u32,
15661        direction: ExpandExcerptDirection,
15662
15663        cx: &mut Context<Self>,
15664    ) {
15665        let selections = self.selections.disjoint_anchors_arc();
15666
15667        let lines = if lines == 0 {
15668            EditorSettings::get_global(cx).expand_excerpt_lines
15669        } else {
15670            lines
15671        };
15672
15673        self.buffer.update(cx, |buffer, cx| {
15674            let snapshot = buffer.snapshot(cx);
15675            let mut excerpt_ids = selections
15676                .iter()
15677                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15678                .collect::<Vec<_>>();
15679            excerpt_ids.sort();
15680            excerpt_ids.dedup();
15681            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15682        })
15683    }
15684
15685    pub fn expand_excerpt(
15686        &mut self,
15687        excerpt: ExcerptId,
15688        direction: ExpandExcerptDirection,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) {
15692        let current_scroll_position = self.scroll_position(cx);
15693        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15694        let mut should_scroll_up = false;
15695
15696        if direction == ExpandExcerptDirection::Down {
15697            let multi_buffer = self.buffer.read(cx);
15698            let snapshot = multi_buffer.snapshot(cx);
15699            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15700                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15701                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15702            {
15703                let buffer_snapshot = buffer.read(cx).snapshot();
15704                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15705                let last_row = buffer_snapshot.max_point().row;
15706                let lines_below = last_row.saturating_sub(excerpt_end_row);
15707                should_scroll_up = lines_below >= lines_to_expand;
15708            }
15709        }
15710
15711        self.buffer.update(cx, |buffer, cx| {
15712            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15713        });
15714
15715        if should_scroll_up {
15716            let new_scroll_position =
15717                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15718            self.set_scroll_position(new_scroll_position, window, cx);
15719        }
15720    }
15721
15722    pub fn go_to_singleton_buffer_point(
15723        &mut self,
15724        point: Point,
15725        window: &mut Window,
15726        cx: &mut Context<Self>,
15727    ) {
15728        self.go_to_singleton_buffer_range(point..point, window, cx);
15729    }
15730
15731    pub fn go_to_singleton_buffer_range(
15732        &mut self,
15733        range: Range<Point>,
15734        window: &mut Window,
15735        cx: &mut Context<Self>,
15736    ) {
15737        let multibuffer = self.buffer().read(cx);
15738        let Some(buffer) = multibuffer.as_singleton() else {
15739            return;
15740        };
15741        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15742            return;
15743        };
15744        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15745            return;
15746        };
15747        self.change_selections(
15748            SelectionEffects::default().nav_history(true),
15749            window,
15750            cx,
15751            |s| s.select_anchor_ranges([start..end]),
15752        );
15753    }
15754
15755    pub fn go_to_diagnostic(
15756        &mut self,
15757        action: &GoToDiagnostic,
15758        window: &mut Window,
15759        cx: &mut Context<Self>,
15760    ) {
15761        if !self.diagnostics_enabled() {
15762            return;
15763        }
15764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15765        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15766    }
15767
15768    pub fn go_to_prev_diagnostic(
15769        &mut self,
15770        action: &GoToPreviousDiagnostic,
15771        window: &mut Window,
15772        cx: &mut Context<Self>,
15773    ) {
15774        if !self.diagnostics_enabled() {
15775            return;
15776        }
15777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15778        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15779    }
15780
15781    pub fn go_to_diagnostic_impl(
15782        &mut self,
15783        direction: Direction,
15784        severity: GoToDiagnosticSeverityFilter,
15785        window: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) {
15788        let buffer = self.buffer.read(cx).snapshot(cx);
15789        let selection = self.selections.newest::<usize>(cx);
15790
15791        let mut active_group_id = None;
15792        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15793            && active_group.active_range.start.to_offset(&buffer) == selection.start
15794        {
15795            active_group_id = Some(active_group.group_id);
15796        }
15797
15798        fn filtered(
15799            snapshot: EditorSnapshot,
15800            severity: GoToDiagnosticSeverityFilter,
15801            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15802        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15803            diagnostics
15804                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15805                .filter(|entry| entry.range.start != entry.range.end)
15806                .filter(|entry| !entry.diagnostic.is_unnecessary)
15807                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15808        }
15809
15810        let snapshot = self.snapshot(window, cx);
15811        let before = filtered(
15812            snapshot.clone(),
15813            severity,
15814            buffer
15815                .diagnostics_in_range(0..selection.start)
15816                .filter(|entry| entry.range.start <= selection.start),
15817        );
15818        let after = filtered(
15819            snapshot,
15820            severity,
15821            buffer
15822                .diagnostics_in_range(selection.start..buffer.len())
15823                .filter(|entry| entry.range.start >= selection.start),
15824        );
15825
15826        let mut found: Option<DiagnosticEntry<usize>> = None;
15827        if direction == Direction::Prev {
15828            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15829            {
15830                for diagnostic in prev_diagnostics.into_iter().rev() {
15831                    if diagnostic.range.start != selection.start
15832                        || active_group_id
15833                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15834                    {
15835                        found = Some(diagnostic);
15836                        break 'outer;
15837                    }
15838                }
15839            }
15840        } else {
15841            for diagnostic in after.chain(before) {
15842                if diagnostic.range.start != selection.start
15843                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15844                {
15845                    found = Some(diagnostic);
15846                    break;
15847                }
15848            }
15849        }
15850        let Some(next_diagnostic) = found else {
15851            return;
15852        };
15853
15854        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15855        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15856            return;
15857        };
15858        self.change_selections(Default::default(), window, cx, |s| {
15859            s.select_ranges(vec![
15860                next_diagnostic.range.start..next_diagnostic.range.start,
15861            ])
15862        });
15863        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15864        self.refresh_edit_prediction(false, true, window, cx);
15865    }
15866
15867    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15869        let snapshot = self.snapshot(window, cx);
15870        let selection = self.selections.newest::<Point>(cx);
15871        self.go_to_hunk_before_or_after_position(
15872            &snapshot,
15873            selection.head(),
15874            Direction::Next,
15875            window,
15876            cx,
15877        );
15878    }
15879
15880    pub fn go_to_hunk_before_or_after_position(
15881        &mut self,
15882        snapshot: &EditorSnapshot,
15883        position: Point,
15884        direction: Direction,
15885        window: &mut Window,
15886        cx: &mut Context<Editor>,
15887    ) {
15888        let row = if direction == Direction::Next {
15889            self.hunk_after_position(snapshot, position)
15890                .map(|hunk| hunk.row_range.start)
15891        } else {
15892            self.hunk_before_position(snapshot, position)
15893        };
15894
15895        if let Some(row) = row {
15896            let destination = Point::new(row.0, 0);
15897            let autoscroll = Autoscroll::center();
15898
15899            self.unfold_ranges(&[destination..destination], false, false, cx);
15900            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15901                s.select_ranges([destination..destination]);
15902            });
15903        }
15904    }
15905
15906    fn hunk_after_position(
15907        &mut self,
15908        snapshot: &EditorSnapshot,
15909        position: Point,
15910    ) -> Option<MultiBufferDiffHunk> {
15911        snapshot
15912            .buffer_snapshot
15913            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15914            .find(|hunk| hunk.row_range.start.0 > position.row)
15915            .or_else(|| {
15916                snapshot
15917                    .buffer_snapshot
15918                    .diff_hunks_in_range(Point::zero()..position)
15919                    .find(|hunk| hunk.row_range.end.0 < position.row)
15920            })
15921    }
15922
15923    fn go_to_prev_hunk(
15924        &mut self,
15925        _: &GoToPreviousHunk,
15926        window: &mut Window,
15927        cx: &mut Context<Self>,
15928    ) {
15929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15930        let snapshot = self.snapshot(window, cx);
15931        let selection = self.selections.newest::<Point>(cx);
15932        self.go_to_hunk_before_or_after_position(
15933            &snapshot,
15934            selection.head(),
15935            Direction::Prev,
15936            window,
15937            cx,
15938        );
15939    }
15940
15941    fn hunk_before_position(
15942        &mut self,
15943        snapshot: &EditorSnapshot,
15944        position: Point,
15945    ) -> Option<MultiBufferRow> {
15946        snapshot
15947            .buffer_snapshot
15948            .diff_hunk_before(position)
15949            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15950    }
15951
15952    fn go_to_next_change(
15953        &mut self,
15954        _: &GoToNextChange,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) {
15958        if let Some(selections) = self
15959            .change_list
15960            .next_change(1, Direction::Next)
15961            .map(|s| s.to_vec())
15962        {
15963            self.change_selections(Default::default(), window, cx, |s| {
15964                let map = s.display_map();
15965                s.select_display_ranges(selections.iter().map(|a| {
15966                    let point = a.to_display_point(&map);
15967                    point..point
15968                }))
15969            })
15970        }
15971    }
15972
15973    fn go_to_previous_change(
15974        &mut self,
15975        _: &GoToPreviousChange,
15976        window: &mut Window,
15977        cx: &mut Context<Self>,
15978    ) {
15979        if let Some(selections) = self
15980            .change_list
15981            .next_change(1, Direction::Prev)
15982            .map(|s| s.to_vec())
15983        {
15984            self.change_selections(Default::default(), window, cx, |s| {
15985                let map = s.display_map();
15986                s.select_display_ranges(selections.iter().map(|a| {
15987                    let point = a.to_display_point(&map);
15988                    point..point
15989                }))
15990            })
15991        }
15992    }
15993
15994    pub fn go_to_next_document_highlight(
15995        &mut self,
15996        _: &GoToNextDocumentHighlight,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16001    }
16002
16003    pub fn go_to_prev_document_highlight(
16004        &mut self,
16005        _: &GoToPreviousDocumentHighlight,
16006        window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) {
16009        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16010    }
16011
16012    pub fn go_to_document_highlight_before_or_after_position(
16013        &mut self,
16014        direction: Direction,
16015        window: &mut Window,
16016        cx: &mut Context<Editor>,
16017    ) {
16018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16019        let snapshot = self.snapshot(window, cx);
16020        let buffer = &snapshot.buffer_snapshot;
16021        let position = self.selections.newest::<Point>(cx).head();
16022        let anchor_position = buffer.anchor_after(position);
16023
16024        // Get all document highlights (both read and write)
16025        let mut all_highlights = Vec::new();
16026
16027        if let Some((_, read_highlights)) = self
16028            .background_highlights
16029            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16030        {
16031            all_highlights.extend(read_highlights.iter());
16032        }
16033
16034        if let Some((_, write_highlights)) = self
16035            .background_highlights
16036            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16037        {
16038            all_highlights.extend(write_highlights.iter());
16039        }
16040
16041        if all_highlights.is_empty() {
16042            return;
16043        }
16044
16045        // Sort highlights by position
16046        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16047
16048        let target_highlight = match direction {
16049            Direction::Next => {
16050                // Find the first highlight after the current position
16051                all_highlights
16052                    .iter()
16053                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16054            }
16055            Direction::Prev => {
16056                // Find the last highlight before the current position
16057                all_highlights
16058                    .iter()
16059                    .rev()
16060                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16061            }
16062        };
16063
16064        if let Some(highlight) = target_highlight {
16065            let destination = highlight.start.to_point(buffer);
16066            let autoscroll = Autoscroll::center();
16067
16068            self.unfold_ranges(&[destination..destination], false, false, cx);
16069            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16070                s.select_ranges([destination..destination]);
16071            });
16072        }
16073    }
16074
16075    fn go_to_line<T: 'static>(
16076        &mut self,
16077        position: Anchor,
16078        highlight_color: Option<Hsla>,
16079        window: &mut Window,
16080        cx: &mut Context<Self>,
16081    ) {
16082        let snapshot = self.snapshot(window, cx).display_snapshot;
16083        let position = position.to_point(&snapshot.buffer_snapshot);
16084        let start = snapshot
16085            .buffer_snapshot
16086            .clip_point(Point::new(position.row, 0), Bias::Left);
16087        let end = start + Point::new(1, 0);
16088        let start = snapshot.buffer_snapshot.anchor_before(start);
16089        let end = snapshot.buffer_snapshot.anchor_before(end);
16090
16091        self.highlight_rows::<T>(
16092            start..end,
16093            highlight_color
16094                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16095            Default::default(),
16096            cx,
16097        );
16098
16099        if self.buffer.read(cx).is_singleton() {
16100            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16101        }
16102    }
16103
16104    pub fn go_to_definition(
16105        &mut self,
16106        _: &GoToDefinition,
16107        window: &mut Window,
16108        cx: &mut Context<Self>,
16109    ) -> Task<Result<Navigated>> {
16110        let definition =
16111            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16112        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16113        cx.spawn_in(window, async move |editor, cx| {
16114            if definition.await? == Navigated::Yes {
16115                return Ok(Navigated::Yes);
16116            }
16117            match fallback_strategy {
16118                GoToDefinitionFallback::None => Ok(Navigated::No),
16119                GoToDefinitionFallback::FindAllReferences => {
16120                    match editor.update_in(cx, |editor, window, cx| {
16121                        editor.find_all_references(&FindAllReferences, window, cx)
16122                    })? {
16123                        Some(references) => references.await,
16124                        None => Ok(Navigated::No),
16125                    }
16126                }
16127            }
16128        })
16129    }
16130
16131    pub fn go_to_declaration(
16132        &mut self,
16133        _: &GoToDeclaration,
16134        window: &mut Window,
16135        cx: &mut Context<Self>,
16136    ) -> Task<Result<Navigated>> {
16137        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16138    }
16139
16140    pub fn go_to_declaration_split(
16141        &mut self,
16142        _: &GoToDeclaration,
16143        window: &mut Window,
16144        cx: &mut Context<Self>,
16145    ) -> Task<Result<Navigated>> {
16146        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16147    }
16148
16149    pub fn go_to_implementation(
16150        &mut self,
16151        _: &GoToImplementation,
16152        window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) -> Task<Result<Navigated>> {
16155        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16156    }
16157
16158    pub fn go_to_implementation_split(
16159        &mut self,
16160        _: &GoToImplementationSplit,
16161        window: &mut Window,
16162        cx: &mut Context<Self>,
16163    ) -> Task<Result<Navigated>> {
16164        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16165    }
16166
16167    pub fn go_to_type_definition(
16168        &mut self,
16169        _: &GoToTypeDefinition,
16170        window: &mut Window,
16171        cx: &mut Context<Self>,
16172    ) -> Task<Result<Navigated>> {
16173        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16174    }
16175
16176    pub fn go_to_definition_split(
16177        &mut self,
16178        _: &GoToDefinitionSplit,
16179        window: &mut Window,
16180        cx: &mut Context<Self>,
16181    ) -> Task<Result<Navigated>> {
16182        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16183    }
16184
16185    pub fn go_to_type_definition_split(
16186        &mut self,
16187        _: &GoToTypeDefinitionSplit,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) -> Task<Result<Navigated>> {
16191        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16192    }
16193
16194    fn go_to_definition_of_kind(
16195        &mut self,
16196        kind: GotoDefinitionKind,
16197        split: bool,
16198        window: &mut Window,
16199        cx: &mut Context<Self>,
16200    ) -> Task<Result<Navigated>> {
16201        let Some(provider) = self.semantics_provider.clone() else {
16202            return Task::ready(Ok(Navigated::No));
16203        };
16204        let head = self.selections.newest::<usize>(cx).head();
16205        let buffer = self.buffer.read(cx);
16206        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16207            return Task::ready(Ok(Navigated::No));
16208        };
16209        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16210            return Task::ready(Ok(Navigated::No));
16211        };
16212
16213        cx.spawn_in(window, async move |editor, cx| {
16214            let Some(definitions) = definitions.await? else {
16215                return Ok(Navigated::No);
16216            };
16217            let navigated = editor
16218                .update_in(cx, |editor, window, cx| {
16219                    editor.navigate_to_hover_links(
16220                        Some(kind),
16221                        definitions
16222                            .into_iter()
16223                            .filter(|location| {
16224                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16225                            })
16226                            .map(HoverLink::Text)
16227                            .collect::<Vec<_>>(),
16228                        split,
16229                        window,
16230                        cx,
16231                    )
16232                })?
16233                .await?;
16234            anyhow::Ok(navigated)
16235        })
16236    }
16237
16238    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16239        let selection = self.selections.newest_anchor();
16240        let head = selection.head();
16241        let tail = selection.tail();
16242
16243        let Some((buffer, start_position)) =
16244            self.buffer.read(cx).text_anchor_for_position(head, cx)
16245        else {
16246            return;
16247        };
16248
16249        let end_position = if head != tail {
16250            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16251                return;
16252            };
16253            Some(pos)
16254        } else {
16255            None
16256        };
16257
16258        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16259            let url = if let Some(end_pos) = end_position {
16260                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16261            } else {
16262                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16263            };
16264
16265            if let Some(url) = url {
16266                editor.update(cx, |_, cx| {
16267                    cx.open_url(&url);
16268                })
16269            } else {
16270                Ok(())
16271            }
16272        });
16273
16274        url_finder.detach();
16275    }
16276
16277    pub fn open_selected_filename(
16278        &mut self,
16279        _: &OpenSelectedFilename,
16280        window: &mut Window,
16281        cx: &mut Context<Self>,
16282    ) {
16283        let Some(workspace) = self.workspace() else {
16284            return;
16285        };
16286
16287        let position = self.selections.newest_anchor().head();
16288
16289        let Some((buffer, buffer_position)) =
16290            self.buffer.read(cx).text_anchor_for_position(position, cx)
16291        else {
16292            return;
16293        };
16294
16295        let project = self.project.clone();
16296
16297        cx.spawn_in(window, async move |_, cx| {
16298            let result = find_file(&buffer, project, buffer_position, cx).await;
16299
16300            if let Some((_, path)) = result {
16301                workspace
16302                    .update_in(cx, |workspace, window, cx| {
16303                        workspace.open_resolved_path(path, window, cx)
16304                    })?
16305                    .await?;
16306            }
16307            anyhow::Ok(())
16308        })
16309        .detach();
16310    }
16311
16312    pub(crate) fn navigate_to_hover_links(
16313        &mut self,
16314        kind: Option<GotoDefinitionKind>,
16315        definitions: Vec<HoverLink>,
16316        split: bool,
16317        window: &mut Window,
16318        cx: &mut Context<Editor>,
16319    ) -> Task<Result<Navigated>> {
16320        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16321        let mut first_url_or_file = None;
16322        let definitions: Vec<_> = definitions
16323            .into_iter()
16324            .filter_map(|def| match def {
16325                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16326                HoverLink::InlayHint(lsp_location, server_id) => {
16327                    let computation =
16328                        self.compute_target_location(lsp_location, server_id, window, cx);
16329                    Some(cx.background_spawn(computation))
16330                }
16331                HoverLink::Url(url) => {
16332                    first_url_or_file = Some(Either::Left(url));
16333                    None
16334                }
16335                HoverLink::File(path) => {
16336                    first_url_or_file = Some(Either::Right(path));
16337                    None
16338                }
16339            })
16340            .collect();
16341
16342        let workspace = self.workspace();
16343
16344        cx.spawn_in(window, async move |editor, acx| {
16345            let mut locations: Vec<Location> = future::join_all(definitions)
16346                .await
16347                .into_iter()
16348                .filter_map(|location| location.transpose())
16349                .collect::<Result<_>>()
16350                .context("location tasks")?;
16351
16352            if locations.len() > 1 {
16353                let Some(workspace) = workspace else {
16354                    return Ok(Navigated::No);
16355                };
16356
16357                let tab_kind = match kind {
16358                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16359                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16360                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16361                    Some(GotoDefinitionKind::Type) => "Types",
16362                };
16363                let title = editor
16364                    .update_in(acx, |_, _, cx| {
16365                        let target = locations
16366                            .iter()
16367                            .map(|location| {
16368                                location
16369                                    .buffer
16370                                    .read(cx)
16371                                    .text_for_range(location.range.clone())
16372                                    .collect::<String>()
16373                            })
16374                            .filter(|text| !text.contains('\n'))
16375                            .unique()
16376                            .take(3)
16377                            .join(", ");
16378                        if target.is_empty() {
16379                            tab_kind.to_owned()
16380                        } else {
16381                            format!("{tab_kind} for {target}")
16382                        }
16383                    })
16384                    .context("buffer title")?;
16385
16386                let opened = workspace
16387                    .update_in(acx, |workspace, window, cx| {
16388                        Self::open_locations_in_multibuffer(
16389                            workspace,
16390                            locations,
16391                            title,
16392                            split,
16393                            MultibufferSelectionMode::First,
16394                            window,
16395                            cx,
16396                        )
16397                    })
16398                    .is_ok();
16399
16400                anyhow::Ok(Navigated::from_bool(opened))
16401            } else if locations.is_empty() {
16402                // If there is one url or file, open it directly
16403                match first_url_or_file {
16404                    Some(Either::Left(url)) => {
16405                        acx.update(|_, cx| cx.open_url(&url))?;
16406                        Ok(Navigated::Yes)
16407                    }
16408                    Some(Either::Right(path)) => {
16409                        let Some(workspace) = workspace else {
16410                            return Ok(Navigated::No);
16411                        };
16412
16413                        workspace
16414                            .update_in(acx, |workspace, window, cx| {
16415                                workspace.open_resolved_path(path, window, cx)
16416                            })?
16417                            .await?;
16418                        Ok(Navigated::Yes)
16419                    }
16420                    None => Ok(Navigated::No),
16421                }
16422            } else {
16423                let Some(workspace) = workspace else {
16424                    return Ok(Navigated::No);
16425                };
16426
16427                let target = locations.pop().unwrap();
16428                editor.update_in(acx, |editor, window, cx| {
16429                    let range = target.range.to_point(target.buffer.read(cx));
16430                    let range = editor.range_for_match(&range);
16431                    let range = collapse_multiline_range(range);
16432
16433                    if !split
16434                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16435                    {
16436                        editor.go_to_singleton_buffer_range(range, window, cx);
16437                    } else {
16438                        let pane = workspace.read(cx).active_pane().clone();
16439                        window.defer(cx, move |window, cx| {
16440                            let target_editor: Entity<Self> =
16441                                workspace.update(cx, |workspace, cx| {
16442                                    let pane = if split {
16443                                        workspace.adjacent_pane(window, cx)
16444                                    } else {
16445                                        workspace.active_pane().clone()
16446                                    };
16447
16448                                    workspace.open_project_item(
16449                                        pane,
16450                                        target.buffer.clone(),
16451                                        true,
16452                                        true,
16453                                        window,
16454                                        cx,
16455                                    )
16456                                });
16457                            target_editor.update(cx, |target_editor, cx| {
16458                                // When selecting a definition in a different buffer, disable the nav history
16459                                // to avoid creating a history entry at the previous cursor location.
16460                                pane.update(cx, |pane, _| pane.disable_history());
16461                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16462                                pane.update(cx, |pane, _| pane.enable_history());
16463                            });
16464                        });
16465                    }
16466                    Navigated::Yes
16467                })
16468            }
16469        })
16470    }
16471
16472    fn compute_target_location(
16473        &self,
16474        lsp_location: lsp::Location,
16475        server_id: LanguageServerId,
16476        window: &mut Window,
16477        cx: &mut Context<Self>,
16478    ) -> Task<anyhow::Result<Option<Location>>> {
16479        let Some(project) = self.project.clone() else {
16480            return Task::ready(Ok(None));
16481        };
16482
16483        cx.spawn_in(window, async move |editor, cx| {
16484            let location_task = editor.update(cx, |_, cx| {
16485                project.update(cx, |project, cx| {
16486                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16487                })
16488            })?;
16489            let location = Some({
16490                let target_buffer_handle = location_task.await.context("open local buffer")?;
16491                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16492                    let target_start = target_buffer
16493                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16494                    let target_end = target_buffer
16495                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16496                    target_buffer.anchor_after(target_start)
16497                        ..target_buffer.anchor_before(target_end)
16498                })?;
16499                Location {
16500                    buffer: target_buffer_handle,
16501                    range,
16502                }
16503            });
16504            Ok(location)
16505        })
16506    }
16507
16508    pub fn find_all_references(
16509        &mut self,
16510        _: &FindAllReferences,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) -> Option<Task<Result<Navigated>>> {
16514        let selection = self.selections.newest::<usize>(cx);
16515        let multi_buffer = self.buffer.read(cx);
16516        let head = selection.head();
16517
16518        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16519        let head_anchor = multi_buffer_snapshot.anchor_at(
16520            head,
16521            if head < selection.tail() {
16522                Bias::Right
16523            } else {
16524                Bias::Left
16525            },
16526        );
16527
16528        match self
16529            .find_all_references_task_sources
16530            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16531        {
16532            Ok(_) => {
16533                log::info!(
16534                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16535                );
16536                return None;
16537            }
16538            Err(i) => {
16539                self.find_all_references_task_sources.insert(i, head_anchor);
16540            }
16541        }
16542
16543        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16544        let workspace = self.workspace()?;
16545        let project = workspace.read(cx).project().clone();
16546        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16547        Some(cx.spawn_in(window, async move |editor, cx| {
16548            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16549                if let Ok(i) = editor
16550                    .find_all_references_task_sources
16551                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16552                {
16553                    editor.find_all_references_task_sources.remove(i);
16554                }
16555            });
16556
16557            let Some(locations) = references.await? else {
16558                return anyhow::Ok(Navigated::No);
16559            };
16560            if locations.is_empty() {
16561                return anyhow::Ok(Navigated::No);
16562            }
16563
16564            workspace.update_in(cx, |workspace, window, cx| {
16565                let target = locations
16566                    .iter()
16567                    .map(|location| {
16568                        location
16569                            .buffer
16570                            .read(cx)
16571                            .text_for_range(location.range.clone())
16572                            .collect::<String>()
16573                    })
16574                    .filter(|text| !text.contains('\n'))
16575                    .unique()
16576                    .take(3)
16577                    .join(", ");
16578                let title = if target.is_empty() {
16579                    "References".to_owned()
16580                } else {
16581                    format!("References to {target}")
16582                };
16583                Self::open_locations_in_multibuffer(
16584                    workspace,
16585                    locations,
16586                    title,
16587                    false,
16588                    MultibufferSelectionMode::First,
16589                    window,
16590                    cx,
16591                );
16592                Navigated::Yes
16593            })
16594        }))
16595    }
16596
16597    /// Opens a multibuffer with the given project locations in it
16598    pub fn open_locations_in_multibuffer(
16599        workspace: &mut Workspace,
16600        mut locations: Vec<Location>,
16601        title: String,
16602        split: bool,
16603        multibuffer_selection_mode: MultibufferSelectionMode,
16604        window: &mut Window,
16605        cx: &mut Context<Workspace>,
16606    ) {
16607        if locations.is_empty() {
16608            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16609            return;
16610        }
16611
16612        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16613
16614        let mut locations = locations.into_iter().peekable();
16615        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16616        let capability = workspace.project().read(cx).capability();
16617
16618        // a key to find existing multibuffer editors with the same set of locations
16619        // to prevent us from opening more and more multibuffer tabs for searches and the like
16620        let mut key = (title.clone(), vec![]);
16621        let excerpt_buffer = cx.new(|cx| {
16622            let key = &mut key.1;
16623            let mut multibuffer = MultiBuffer::new(capability);
16624            while let Some(location) = locations.next() {
16625                let buffer = location.buffer.read(cx);
16626                let mut ranges_for_buffer = Vec::new();
16627                let range = location.range.to_point(buffer);
16628                ranges_for_buffer.push(range.clone());
16629
16630                while let Some(next_location) =
16631                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16632                {
16633                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16634                }
16635
16636                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16637                key.push((
16638                    location.buffer.read(cx).remote_id(),
16639                    ranges_for_buffer.clone(),
16640                ));
16641                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16642                    PathKey::for_buffer(&location.buffer, cx),
16643                    location.buffer.clone(),
16644                    ranges_for_buffer,
16645                    multibuffer_context_lines(cx),
16646                    cx,
16647                );
16648                ranges.extend(new_ranges)
16649            }
16650
16651            multibuffer.with_title(title)
16652        });
16653        let existing = workspace.active_pane().update(cx, |pane, cx| {
16654            pane.items()
16655                .filter_map(|item| item.downcast::<Editor>())
16656                .find(|editor| {
16657                    editor
16658                        .read(cx)
16659                        .lookup_key
16660                        .as_ref()
16661                        .and_then(|it| {
16662                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16663                        })
16664                        .is_some_and(|it| *it == key)
16665                })
16666        });
16667        let editor = existing.unwrap_or_else(|| {
16668            cx.new(|cx| {
16669                let mut editor = Editor::for_multibuffer(
16670                    excerpt_buffer,
16671                    Some(workspace.project().clone()),
16672                    window,
16673                    cx,
16674                );
16675                editor.lookup_key = Some(Box::new(key));
16676                editor
16677            })
16678        });
16679        editor.update(cx, |editor, cx| {
16680            match multibuffer_selection_mode {
16681                MultibufferSelectionMode::First => {
16682                    if let Some(first_range) = ranges.first() {
16683                        editor.change_selections(
16684                            SelectionEffects::no_scroll(),
16685                            window,
16686                            cx,
16687                            |selections| {
16688                                selections.clear_disjoint();
16689                                selections
16690                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16691                            },
16692                        );
16693                    }
16694                    editor.highlight_background::<Self>(
16695                        &ranges,
16696                        |theme| theme.colors().editor_highlighted_line_background,
16697                        cx,
16698                    );
16699                }
16700                MultibufferSelectionMode::All => {
16701                    editor.change_selections(
16702                        SelectionEffects::no_scroll(),
16703                        window,
16704                        cx,
16705                        |selections| {
16706                            selections.clear_disjoint();
16707                            selections.select_anchor_ranges(ranges);
16708                        },
16709                    );
16710                }
16711            }
16712            editor.register_buffers_with_language_servers(cx);
16713        });
16714
16715        let item = Box::new(editor);
16716        let item_id = item.item_id();
16717
16718        if split {
16719            workspace.split_item(SplitDirection::Right, item, window, cx);
16720        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16721            let (preview_item_id, preview_item_idx) =
16722                workspace.active_pane().read_with(cx, |pane, _| {
16723                    (pane.preview_item_id(), pane.preview_item_idx())
16724                });
16725
16726            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16727
16728            if let Some(preview_item_id) = preview_item_id {
16729                workspace.active_pane().update(cx, |pane, cx| {
16730                    pane.remove_item(preview_item_id, false, false, window, cx);
16731                });
16732            }
16733        } else {
16734            workspace.add_item_to_active_pane(item, None, true, window, cx);
16735        }
16736        workspace.active_pane().update(cx, |pane, cx| {
16737            pane.set_preview_item_id(Some(item_id), cx);
16738        });
16739    }
16740
16741    pub fn rename(
16742        &mut self,
16743        _: &Rename,
16744        window: &mut Window,
16745        cx: &mut Context<Self>,
16746    ) -> Option<Task<Result<()>>> {
16747        use language::ToOffset as _;
16748
16749        let provider = self.semantics_provider.clone()?;
16750        let selection = self.selections.newest_anchor().clone();
16751        let (cursor_buffer, cursor_buffer_position) = self
16752            .buffer
16753            .read(cx)
16754            .text_anchor_for_position(selection.head(), cx)?;
16755        let (tail_buffer, cursor_buffer_position_end) = self
16756            .buffer
16757            .read(cx)
16758            .text_anchor_for_position(selection.tail(), cx)?;
16759        if tail_buffer != cursor_buffer {
16760            return None;
16761        }
16762
16763        let snapshot = cursor_buffer.read(cx).snapshot();
16764        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16765        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16766        let prepare_rename = provider
16767            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16768            .unwrap_or_else(|| Task::ready(Ok(None)));
16769        drop(snapshot);
16770
16771        Some(cx.spawn_in(window, async move |this, cx| {
16772            let rename_range = if let Some(range) = prepare_rename.await? {
16773                Some(range)
16774            } else {
16775                this.update(cx, |this, cx| {
16776                    let buffer = this.buffer.read(cx).snapshot(cx);
16777                    let mut buffer_highlights = this
16778                        .document_highlights_for_position(selection.head(), &buffer)
16779                        .filter(|highlight| {
16780                            highlight.start.excerpt_id == selection.head().excerpt_id
16781                                && highlight.end.excerpt_id == selection.head().excerpt_id
16782                        });
16783                    buffer_highlights
16784                        .next()
16785                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16786                })?
16787            };
16788            if let Some(rename_range) = rename_range {
16789                this.update_in(cx, |this, window, cx| {
16790                    let snapshot = cursor_buffer.read(cx).snapshot();
16791                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16792                    let cursor_offset_in_rename_range =
16793                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16794                    let cursor_offset_in_rename_range_end =
16795                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16796
16797                    this.take_rename(false, window, cx);
16798                    let buffer = this.buffer.read(cx).read(cx);
16799                    let cursor_offset = selection.head().to_offset(&buffer);
16800                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16801                    let rename_end = rename_start + rename_buffer_range.len();
16802                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16803                    let mut old_highlight_id = None;
16804                    let old_name: Arc<str> = buffer
16805                        .chunks(rename_start..rename_end, true)
16806                        .map(|chunk| {
16807                            if old_highlight_id.is_none() {
16808                                old_highlight_id = chunk.syntax_highlight_id;
16809                            }
16810                            chunk.text
16811                        })
16812                        .collect::<String>()
16813                        .into();
16814
16815                    drop(buffer);
16816
16817                    // Position the selection in the rename editor so that it matches the current selection.
16818                    this.show_local_selections = false;
16819                    let rename_editor = cx.new(|cx| {
16820                        let mut editor = Editor::single_line(window, cx);
16821                        editor.buffer.update(cx, |buffer, cx| {
16822                            buffer.edit([(0..0, old_name.clone())], None, cx)
16823                        });
16824                        let rename_selection_range = match cursor_offset_in_rename_range
16825                            .cmp(&cursor_offset_in_rename_range_end)
16826                        {
16827                            Ordering::Equal => {
16828                                editor.select_all(&SelectAll, window, cx);
16829                                return editor;
16830                            }
16831                            Ordering::Less => {
16832                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16833                            }
16834                            Ordering::Greater => {
16835                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16836                            }
16837                        };
16838                        if rename_selection_range.end > old_name.len() {
16839                            editor.select_all(&SelectAll, window, cx);
16840                        } else {
16841                            editor.change_selections(Default::default(), window, cx, |s| {
16842                                s.select_ranges([rename_selection_range]);
16843                            });
16844                        }
16845                        editor
16846                    });
16847                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16848                        if e == &EditorEvent::Focused {
16849                            cx.emit(EditorEvent::FocusedIn)
16850                        }
16851                    })
16852                    .detach();
16853
16854                    let write_highlights =
16855                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16856                    let read_highlights =
16857                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16858                    let ranges = write_highlights
16859                        .iter()
16860                        .flat_map(|(_, ranges)| ranges.iter())
16861                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16862                        .cloned()
16863                        .collect();
16864
16865                    this.highlight_text::<Rename>(
16866                        ranges,
16867                        HighlightStyle {
16868                            fade_out: Some(0.6),
16869                            ..Default::default()
16870                        },
16871                        cx,
16872                    );
16873                    let rename_focus_handle = rename_editor.focus_handle(cx);
16874                    window.focus(&rename_focus_handle);
16875                    let block_id = this.insert_blocks(
16876                        [BlockProperties {
16877                            style: BlockStyle::Flex,
16878                            placement: BlockPlacement::Below(range.start),
16879                            height: Some(1),
16880                            render: Arc::new({
16881                                let rename_editor = rename_editor.clone();
16882                                move |cx: &mut BlockContext| {
16883                                    let mut text_style = cx.editor_style.text.clone();
16884                                    if let Some(highlight_style) = old_highlight_id
16885                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16886                                    {
16887                                        text_style = text_style.highlight(highlight_style);
16888                                    }
16889                                    div()
16890                                        .block_mouse_except_scroll()
16891                                        .pl(cx.anchor_x)
16892                                        .child(EditorElement::new(
16893                                            &rename_editor,
16894                                            EditorStyle {
16895                                                background: cx.theme().system().transparent,
16896                                                local_player: cx.editor_style.local_player,
16897                                                text: text_style,
16898                                                scrollbar_width: cx.editor_style.scrollbar_width,
16899                                                syntax: cx.editor_style.syntax.clone(),
16900                                                status: cx.editor_style.status.clone(),
16901                                                inlay_hints_style: HighlightStyle {
16902                                                    font_weight: Some(FontWeight::BOLD),
16903                                                    ..make_inlay_hints_style(cx.app)
16904                                                },
16905                                                edit_prediction_styles: make_suggestion_styles(
16906                                                    cx.app,
16907                                                ),
16908                                                ..EditorStyle::default()
16909                                            },
16910                                        ))
16911                                        .into_any_element()
16912                                }
16913                            }),
16914                            priority: 0,
16915                        }],
16916                        Some(Autoscroll::fit()),
16917                        cx,
16918                    )[0];
16919                    this.pending_rename = Some(RenameState {
16920                        range,
16921                        old_name,
16922                        editor: rename_editor,
16923                        block_id,
16924                    });
16925                })?;
16926            }
16927
16928            Ok(())
16929        }))
16930    }
16931
16932    pub fn confirm_rename(
16933        &mut self,
16934        _: &ConfirmRename,
16935        window: &mut Window,
16936        cx: &mut Context<Self>,
16937    ) -> Option<Task<Result<()>>> {
16938        let rename = self.take_rename(false, window, cx)?;
16939        let workspace = self.workspace()?.downgrade();
16940        let (buffer, start) = self
16941            .buffer
16942            .read(cx)
16943            .text_anchor_for_position(rename.range.start, cx)?;
16944        let (end_buffer, _) = self
16945            .buffer
16946            .read(cx)
16947            .text_anchor_for_position(rename.range.end, cx)?;
16948        if buffer != end_buffer {
16949            return None;
16950        }
16951
16952        let old_name = rename.old_name;
16953        let new_name = rename.editor.read(cx).text(cx);
16954
16955        let rename = self.semantics_provider.as_ref()?.perform_rename(
16956            &buffer,
16957            start,
16958            new_name.clone(),
16959            cx,
16960        )?;
16961
16962        Some(cx.spawn_in(window, async move |editor, cx| {
16963            let project_transaction = rename.await?;
16964            Self::open_project_transaction(
16965                &editor,
16966                workspace,
16967                project_transaction,
16968                format!("Rename: {}{}", old_name, new_name),
16969                cx,
16970            )
16971            .await?;
16972
16973            editor.update(cx, |editor, cx| {
16974                editor.refresh_document_highlights(cx);
16975            })?;
16976            Ok(())
16977        }))
16978    }
16979
16980    fn take_rename(
16981        &mut self,
16982        moving_cursor: bool,
16983        window: &mut Window,
16984        cx: &mut Context<Self>,
16985    ) -> Option<RenameState> {
16986        let rename = self.pending_rename.take()?;
16987        if rename.editor.focus_handle(cx).is_focused(window) {
16988            window.focus(&self.focus_handle);
16989        }
16990
16991        self.remove_blocks(
16992            [rename.block_id].into_iter().collect(),
16993            Some(Autoscroll::fit()),
16994            cx,
16995        );
16996        self.clear_highlights::<Rename>(cx);
16997        self.show_local_selections = true;
16998
16999        if moving_cursor {
17000            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17001                editor.selections.newest::<usize>(cx).head()
17002            });
17003
17004            // Update the selection to match the position of the selection inside
17005            // the rename editor.
17006            let snapshot = self.buffer.read(cx).read(cx);
17007            let rename_range = rename.range.to_offset(&snapshot);
17008            let cursor_in_editor = snapshot
17009                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17010                .min(rename_range.end);
17011            drop(snapshot);
17012
17013            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17014                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17015            });
17016        } else {
17017            self.refresh_document_highlights(cx);
17018        }
17019
17020        Some(rename)
17021    }
17022
17023    pub fn pending_rename(&self) -> Option<&RenameState> {
17024        self.pending_rename.as_ref()
17025    }
17026
17027    fn format(
17028        &mut self,
17029        _: &Format,
17030        window: &mut Window,
17031        cx: &mut Context<Self>,
17032    ) -> Option<Task<Result<()>>> {
17033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17034
17035        let project = match &self.project {
17036            Some(project) => project.clone(),
17037            None => return None,
17038        };
17039
17040        Some(self.perform_format(
17041            project,
17042            FormatTrigger::Manual,
17043            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17044            window,
17045            cx,
17046        ))
17047    }
17048
17049    fn format_selections(
17050        &mut self,
17051        _: &FormatSelections,
17052        window: &mut Window,
17053        cx: &mut Context<Self>,
17054    ) -> Option<Task<Result<()>>> {
17055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17056
17057        let project = match &self.project {
17058            Some(project) => project.clone(),
17059            None => return None,
17060        };
17061
17062        let ranges = self
17063            .selections
17064            .all_adjusted(cx)
17065            .into_iter()
17066            .map(|selection| selection.range())
17067            .collect_vec();
17068
17069        Some(self.perform_format(
17070            project,
17071            FormatTrigger::Manual,
17072            FormatTarget::Ranges(ranges),
17073            window,
17074            cx,
17075        ))
17076    }
17077
17078    fn perform_format(
17079        &mut self,
17080        project: Entity<Project>,
17081        trigger: FormatTrigger,
17082        target: FormatTarget,
17083        window: &mut Window,
17084        cx: &mut Context<Self>,
17085    ) -> Task<Result<()>> {
17086        let buffer = self.buffer.clone();
17087        let (buffers, target) = match target {
17088            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17089            FormatTarget::Ranges(selection_ranges) => {
17090                let multi_buffer = buffer.read(cx);
17091                let snapshot = multi_buffer.read(cx);
17092                let mut buffers = HashSet::default();
17093                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17094                    BTreeMap::new();
17095                for selection_range in selection_ranges {
17096                    for (buffer, buffer_range, _) in
17097                        snapshot.range_to_buffer_ranges(selection_range)
17098                    {
17099                        let buffer_id = buffer.remote_id();
17100                        let start = buffer.anchor_before(buffer_range.start);
17101                        let end = buffer.anchor_after(buffer_range.end);
17102                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17103                        buffer_id_to_ranges
17104                            .entry(buffer_id)
17105                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17106                            .or_insert_with(|| vec![start..end]);
17107                    }
17108                }
17109                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17110            }
17111        };
17112
17113        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17114        let selections_prev = transaction_id_prev
17115            .and_then(|transaction_id_prev| {
17116                // default to selections as they were after the last edit, if we have them,
17117                // instead of how they are now.
17118                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17119                // will take you back to where you made the last edit, instead of staying where you scrolled
17120                self.selection_history
17121                    .transaction(transaction_id_prev)
17122                    .map(|t| t.0.clone())
17123            })
17124            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17125
17126        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17127        let format = project.update(cx, |project, cx| {
17128            project.format(buffers, target, true, trigger, cx)
17129        });
17130
17131        cx.spawn_in(window, async move |editor, cx| {
17132            let transaction = futures::select_biased! {
17133                transaction = format.log_err().fuse() => transaction,
17134                () = timeout => {
17135                    log::warn!("timed out waiting for formatting");
17136                    None
17137                }
17138            };
17139
17140            buffer
17141                .update(cx, |buffer, cx| {
17142                    if let Some(transaction) = transaction
17143                        && !buffer.is_singleton()
17144                    {
17145                        buffer.push_transaction(&transaction.0, cx);
17146                    }
17147                    cx.notify();
17148                })
17149                .ok();
17150
17151            if let Some(transaction_id_now) =
17152                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17153            {
17154                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17155                if has_new_transaction {
17156                    _ = editor.update(cx, |editor, _| {
17157                        editor
17158                            .selection_history
17159                            .insert_transaction(transaction_id_now, selections_prev);
17160                    });
17161                }
17162            }
17163
17164            Ok(())
17165        })
17166    }
17167
17168    fn organize_imports(
17169        &mut self,
17170        _: &OrganizeImports,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) -> Option<Task<Result<()>>> {
17174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17175        let project = match &self.project {
17176            Some(project) => project.clone(),
17177            None => return None,
17178        };
17179        Some(self.perform_code_action_kind(
17180            project,
17181            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17182            window,
17183            cx,
17184        ))
17185    }
17186
17187    fn perform_code_action_kind(
17188        &mut self,
17189        project: Entity<Project>,
17190        kind: CodeActionKind,
17191        window: &mut Window,
17192        cx: &mut Context<Self>,
17193    ) -> Task<Result<()>> {
17194        let buffer = self.buffer.clone();
17195        let buffers = buffer.read(cx).all_buffers();
17196        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17197        let apply_action = project.update(cx, |project, cx| {
17198            project.apply_code_action_kind(buffers, kind, true, cx)
17199        });
17200        cx.spawn_in(window, async move |_, cx| {
17201            let transaction = futures::select_biased! {
17202                () = timeout => {
17203                    log::warn!("timed out waiting for executing code action");
17204                    None
17205                }
17206                transaction = apply_action.log_err().fuse() => transaction,
17207            };
17208            buffer
17209                .update(cx, |buffer, cx| {
17210                    // check if we need this
17211                    if let Some(transaction) = transaction
17212                        && !buffer.is_singleton()
17213                    {
17214                        buffer.push_transaction(&transaction.0, cx);
17215                    }
17216                    cx.notify();
17217                })
17218                .ok();
17219            Ok(())
17220        })
17221    }
17222
17223    pub fn restart_language_server(
17224        &mut self,
17225        _: &RestartLanguageServer,
17226        _: &mut Window,
17227        cx: &mut Context<Self>,
17228    ) {
17229        if let Some(project) = self.project.clone() {
17230            self.buffer.update(cx, |multi_buffer, cx| {
17231                project.update(cx, |project, cx| {
17232                    project.restart_language_servers_for_buffers(
17233                        multi_buffer.all_buffers().into_iter().collect(),
17234                        HashSet::default(),
17235                        cx,
17236                    );
17237                });
17238            })
17239        }
17240    }
17241
17242    pub fn stop_language_server(
17243        &mut self,
17244        _: &StopLanguageServer,
17245        _: &mut Window,
17246        cx: &mut Context<Self>,
17247    ) {
17248        if let Some(project) = self.project.clone() {
17249            self.buffer.update(cx, |multi_buffer, cx| {
17250                project.update(cx, |project, cx| {
17251                    project.stop_language_servers_for_buffers(
17252                        multi_buffer.all_buffers().into_iter().collect(),
17253                        HashSet::default(),
17254                        cx,
17255                    );
17256                    cx.emit(project::Event::RefreshInlayHints);
17257                });
17258            });
17259        }
17260    }
17261
17262    fn cancel_language_server_work(
17263        workspace: &mut Workspace,
17264        _: &actions::CancelLanguageServerWork,
17265        _: &mut Window,
17266        cx: &mut Context<Workspace>,
17267    ) {
17268        let project = workspace.project();
17269        let buffers = workspace
17270            .active_item(cx)
17271            .and_then(|item| item.act_as::<Editor>(cx))
17272            .map_or(HashSet::default(), |editor| {
17273                editor.read(cx).buffer.read(cx).all_buffers()
17274            });
17275        project.update(cx, |project, cx| {
17276            project.cancel_language_server_work_for_buffers(buffers, cx);
17277        });
17278    }
17279
17280    fn show_character_palette(
17281        &mut self,
17282        _: &ShowCharacterPalette,
17283        window: &mut Window,
17284        _: &mut Context<Self>,
17285    ) {
17286        window.show_character_palette();
17287    }
17288
17289    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17290        if !self.diagnostics_enabled() {
17291            return;
17292        }
17293
17294        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17295            let buffer = self.buffer.read(cx).snapshot(cx);
17296            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17297            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17298            let is_valid = buffer
17299                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17300                .any(|entry| {
17301                    entry.diagnostic.is_primary
17302                        && !entry.range.is_empty()
17303                        && entry.range.start == primary_range_start
17304                        && entry.diagnostic.message == active_diagnostics.active_message
17305                });
17306
17307            if !is_valid {
17308                self.dismiss_diagnostics(cx);
17309            }
17310        }
17311    }
17312
17313    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17314        match &self.active_diagnostics {
17315            ActiveDiagnostic::Group(group) => Some(group),
17316            _ => None,
17317        }
17318    }
17319
17320    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17321        if !self.diagnostics_enabled() {
17322            return;
17323        }
17324        self.dismiss_diagnostics(cx);
17325        self.active_diagnostics = ActiveDiagnostic::All;
17326    }
17327
17328    fn activate_diagnostics(
17329        &mut self,
17330        buffer_id: BufferId,
17331        diagnostic: DiagnosticEntry<usize>,
17332        window: &mut Window,
17333        cx: &mut Context<Self>,
17334    ) {
17335        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17336            return;
17337        }
17338        self.dismiss_diagnostics(cx);
17339        let snapshot = self.snapshot(window, cx);
17340        let buffer = self.buffer.read(cx).snapshot(cx);
17341        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17342            return;
17343        };
17344
17345        let diagnostic_group = buffer
17346            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17347            .collect::<Vec<_>>();
17348
17349        let blocks =
17350            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17351
17352        let blocks = self.display_map.update(cx, |display_map, cx| {
17353            display_map.insert_blocks(blocks, cx).into_iter().collect()
17354        });
17355        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17356            active_range: buffer.anchor_before(diagnostic.range.start)
17357                ..buffer.anchor_after(diagnostic.range.end),
17358            active_message: diagnostic.diagnostic.message.clone(),
17359            group_id: diagnostic.diagnostic.group_id,
17360            blocks,
17361        });
17362        cx.notify();
17363    }
17364
17365    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17366        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17367            return;
17368        };
17369
17370        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17371        if let ActiveDiagnostic::Group(group) = prev {
17372            self.display_map.update(cx, |display_map, cx| {
17373                display_map.remove_blocks(group.blocks, cx);
17374            });
17375            cx.notify();
17376        }
17377    }
17378
17379    /// Disable inline diagnostics rendering for this editor.
17380    pub fn disable_inline_diagnostics(&mut self) {
17381        self.inline_diagnostics_enabled = false;
17382        self.inline_diagnostics_update = Task::ready(());
17383        self.inline_diagnostics.clear();
17384    }
17385
17386    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17387        self.diagnostics_enabled = false;
17388        self.dismiss_diagnostics(cx);
17389        self.inline_diagnostics_update = Task::ready(());
17390        self.inline_diagnostics.clear();
17391    }
17392
17393    pub fn disable_word_completions(&mut self) {
17394        self.word_completions_enabled = false;
17395    }
17396
17397    pub fn diagnostics_enabled(&self) -> bool {
17398        self.diagnostics_enabled && self.mode.is_full()
17399    }
17400
17401    pub fn inline_diagnostics_enabled(&self) -> bool {
17402        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17403    }
17404
17405    pub fn show_inline_diagnostics(&self) -> bool {
17406        self.show_inline_diagnostics
17407    }
17408
17409    pub fn toggle_inline_diagnostics(
17410        &mut self,
17411        _: &ToggleInlineDiagnostics,
17412        window: &mut Window,
17413        cx: &mut Context<Editor>,
17414    ) {
17415        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17416        self.refresh_inline_diagnostics(false, window, cx);
17417    }
17418
17419    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17420        self.diagnostics_max_severity = severity;
17421        self.display_map.update(cx, |display_map, _| {
17422            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17423        });
17424    }
17425
17426    pub fn toggle_diagnostics(
17427        &mut self,
17428        _: &ToggleDiagnostics,
17429        window: &mut Window,
17430        cx: &mut Context<Editor>,
17431    ) {
17432        if !self.diagnostics_enabled() {
17433            return;
17434        }
17435
17436        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17437            EditorSettings::get_global(cx)
17438                .diagnostics_max_severity
17439                .filter(|severity| severity != &DiagnosticSeverity::Off)
17440                .unwrap_or(DiagnosticSeverity::Hint)
17441        } else {
17442            DiagnosticSeverity::Off
17443        };
17444        self.set_max_diagnostics_severity(new_severity, cx);
17445        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17446            self.active_diagnostics = ActiveDiagnostic::None;
17447            self.inline_diagnostics_update = Task::ready(());
17448            self.inline_diagnostics.clear();
17449        } else {
17450            self.refresh_inline_diagnostics(false, window, cx);
17451        }
17452
17453        cx.notify();
17454    }
17455
17456    pub fn toggle_minimap(
17457        &mut self,
17458        _: &ToggleMinimap,
17459        window: &mut Window,
17460        cx: &mut Context<Editor>,
17461    ) {
17462        if self.supports_minimap(cx) {
17463            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17464        }
17465    }
17466
17467    fn refresh_inline_diagnostics(
17468        &mut self,
17469        debounce: bool,
17470        window: &mut Window,
17471        cx: &mut Context<Self>,
17472    ) {
17473        let max_severity = ProjectSettings::get_global(cx)
17474            .diagnostics
17475            .inline
17476            .max_severity
17477            .unwrap_or(self.diagnostics_max_severity);
17478
17479        if !self.inline_diagnostics_enabled()
17480            || !self.show_inline_diagnostics
17481            || max_severity == DiagnosticSeverity::Off
17482        {
17483            self.inline_diagnostics_update = Task::ready(());
17484            self.inline_diagnostics.clear();
17485            return;
17486        }
17487
17488        let debounce_ms = ProjectSettings::get_global(cx)
17489            .diagnostics
17490            .inline
17491            .update_debounce_ms;
17492        let debounce = if debounce && debounce_ms > 0 {
17493            Some(Duration::from_millis(debounce_ms))
17494        } else {
17495            None
17496        };
17497        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17498            if let Some(debounce) = debounce {
17499                cx.background_executor().timer(debounce).await;
17500            }
17501            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17502                editor
17503                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17504                    .ok()
17505            }) else {
17506                return;
17507            };
17508
17509            let new_inline_diagnostics = cx
17510                .background_spawn(async move {
17511                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17512                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17513                        let message = diagnostic_entry
17514                            .diagnostic
17515                            .message
17516                            .split_once('\n')
17517                            .map(|(line, _)| line)
17518                            .map(SharedString::new)
17519                            .unwrap_or_else(|| {
17520                                SharedString::from(diagnostic_entry.diagnostic.message)
17521                            });
17522                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17523                        let (Ok(i) | Err(i)) = inline_diagnostics
17524                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17525                        inline_diagnostics.insert(
17526                            i,
17527                            (
17528                                start_anchor,
17529                                InlineDiagnostic {
17530                                    message,
17531                                    group_id: diagnostic_entry.diagnostic.group_id,
17532                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17533                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17534                                    severity: diagnostic_entry.diagnostic.severity,
17535                                },
17536                            ),
17537                        );
17538                    }
17539                    inline_diagnostics
17540                })
17541                .await;
17542
17543            editor
17544                .update(cx, |editor, cx| {
17545                    editor.inline_diagnostics = new_inline_diagnostics;
17546                    cx.notify();
17547                })
17548                .ok();
17549        });
17550    }
17551
17552    fn pull_diagnostics(
17553        &mut self,
17554        buffer_id: Option<BufferId>,
17555        window: &Window,
17556        cx: &mut Context<Self>,
17557    ) -> Option<()> {
17558        if !self.mode().is_full() {
17559            return None;
17560        }
17561        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17562            .diagnostics
17563            .lsp_pull_diagnostics;
17564        if !pull_diagnostics_settings.enabled {
17565            return None;
17566        }
17567        let project = self.project()?.downgrade();
17568        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17569        let mut buffers = self.buffer.read(cx).all_buffers();
17570        if let Some(buffer_id) = buffer_id {
17571            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17572        }
17573
17574        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17575            cx.background_executor().timer(debounce).await;
17576
17577            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17578                buffers
17579                    .into_iter()
17580                    .filter_map(|buffer| {
17581                        project
17582                            .update(cx, |project, cx| {
17583                                project.lsp_store().update(cx, |lsp_store, cx| {
17584                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17585                                })
17586                            })
17587                            .ok()
17588                    })
17589                    .collect::<FuturesUnordered<_>>()
17590            }) else {
17591                return;
17592            };
17593
17594            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17595                match pull_task {
17596                    Ok(()) => {
17597                        if editor
17598                            .update_in(cx, |editor, window, cx| {
17599                                editor.update_diagnostics_state(window, cx);
17600                            })
17601                            .is_err()
17602                        {
17603                            return;
17604                        }
17605                    }
17606                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17607                }
17608            }
17609        });
17610
17611        Some(())
17612    }
17613
17614    pub fn set_selections_from_remote(
17615        &mut self,
17616        selections: Vec<Selection<Anchor>>,
17617        pending_selection: Option<Selection<Anchor>>,
17618        window: &mut Window,
17619        cx: &mut Context<Self>,
17620    ) {
17621        let old_cursor_position = self.selections.newest_anchor().head();
17622        self.selections.change_with(cx, |s| {
17623            s.select_anchors(selections);
17624            if let Some(pending_selection) = pending_selection {
17625                s.set_pending(pending_selection, SelectMode::Character);
17626            } else {
17627                s.clear_pending();
17628            }
17629        });
17630        self.selections_did_change(
17631            false,
17632            &old_cursor_position,
17633            SelectionEffects::default(),
17634            window,
17635            cx,
17636        );
17637    }
17638
17639    pub fn transact(
17640        &mut self,
17641        window: &mut Window,
17642        cx: &mut Context<Self>,
17643        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17644    ) -> Option<TransactionId> {
17645        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17646            this.start_transaction_at(Instant::now(), window, cx);
17647            update(this, window, cx);
17648            this.end_transaction_at(Instant::now(), cx)
17649        })
17650    }
17651
17652    pub fn start_transaction_at(
17653        &mut self,
17654        now: Instant,
17655        window: &mut Window,
17656        cx: &mut Context<Self>,
17657    ) -> Option<TransactionId> {
17658        self.end_selection(window, cx);
17659        if let Some(tx_id) = self
17660            .buffer
17661            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17662        {
17663            self.selection_history
17664                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17665            cx.emit(EditorEvent::TransactionBegun {
17666                transaction_id: tx_id,
17667            });
17668            Some(tx_id)
17669        } else {
17670            None
17671        }
17672    }
17673
17674    pub fn end_transaction_at(
17675        &mut self,
17676        now: Instant,
17677        cx: &mut Context<Self>,
17678    ) -> Option<TransactionId> {
17679        if let Some(transaction_id) = self
17680            .buffer
17681            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17682        {
17683            if let Some((_, end_selections)) =
17684                self.selection_history.transaction_mut(transaction_id)
17685            {
17686                *end_selections = Some(self.selections.disjoint_anchors_arc());
17687            } else {
17688                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17689            }
17690
17691            cx.emit(EditorEvent::Edited { transaction_id });
17692            Some(transaction_id)
17693        } else {
17694            None
17695        }
17696    }
17697
17698    pub fn modify_transaction_selection_history(
17699        &mut self,
17700        transaction_id: TransactionId,
17701        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17702    ) -> bool {
17703        self.selection_history
17704            .transaction_mut(transaction_id)
17705            .map(modify)
17706            .is_some()
17707    }
17708
17709    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17710        if self.selection_mark_mode {
17711            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17712                s.move_with(|_, sel| {
17713                    sel.collapse_to(sel.head(), SelectionGoal::None);
17714                });
17715            })
17716        }
17717        self.selection_mark_mode = true;
17718        cx.notify();
17719    }
17720
17721    pub fn swap_selection_ends(
17722        &mut self,
17723        _: &actions::SwapSelectionEnds,
17724        window: &mut Window,
17725        cx: &mut Context<Self>,
17726    ) {
17727        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17728            s.move_with(|_, sel| {
17729                if sel.start != sel.end {
17730                    sel.reversed = !sel.reversed
17731                }
17732            });
17733        });
17734        self.request_autoscroll(Autoscroll::newest(), cx);
17735        cx.notify();
17736    }
17737
17738    pub fn toggle_focus(
17739        workspace: &mut Workspace,
17740        _: &actions::ToggleFocus,
17741        window: &mut Window,
17742        cx: &mut Context<Workspace>,
17743    ) {
17744        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17745            return;
17746        };
17747        workspace.activate_item(&item, true, true, window, cx);
17748    }
17749
17750    pub fn toggle_fold(
17751        &mut self,
17752        _: &actions::ToggleFold,
17753        window: &mut Window,
17754        cx: &mut Context<Self>,
17755    ) {
17756        if self.is_singleton(cx) {
17757            let selection = self.selections.newest::<Point>(cx);
17758
17759            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17760            let range = if selection.is_empty() {
17761                let point = selection.head().to_display_point(&display_map);
17762                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17763                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17764                    .to_point(&display_map);
17765                start..end
17766            } else {
17767                selection.range()
17768            };
17769            if display_map.folds_in_range(range).next().is_some() {
17770                self.unfold_lines(&Default::default(), window, cx)
17771            } else {
17772                self.fold(&Default::default(), window, cx)
17773            }
17774        } else {
17775            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17776            let buffer_ids: HashSet<_> = self
17777                .selections
17778                .disjoint_anchor_ranges()
17779                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17780                .collect();
17781
17782            let should_unfold = buffer_ids
17783                .iter()
17784                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17785
17786            for buffer_id in buffer_ids {
17787                if should_unfold {
17788                    self.unfold_buffer(buffer_id, cx);
17789                } else {
17790                    self.fold_buffer(buffer_id, cx);
17791                }
17792            }
17793        }
17794    }
17795
17796    pub fn toggle_fold_recursive(
17797        &mut self,
17798        _: &actions::ToggleFoldRecursive,
17799        window: &mut Window,
17800        cx: &mut Context<Self>,
17801    ) {
17802        let selection = self.selections.newest::<Point>(cx);
17803
17804        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17805        let range = if selection.is_empty() {
17806            let point = selection.head().to_display_point(&display_map);
17807            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17808            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17809                .to_point(&display_map);
17810            start..end
17811        } else {
17812            selection.range()
17813        };
17814        if display_map.folds_in_range(range).next().is_some() {
17815            self.unfold_recursive(&Default::default(), window, cx)
17816        } else {
17817            self.fold_recursive(&Default::default(), window, cx)
17818        }
17819    }
17820
17821    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17822        if self.is_singleton(cx) {
17823            let mut to_fold = Vec::new();
17824            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17825            let selections = self.selections.all_adjusted(cx);
17826
17827            for selection in selections {
17828                let range = selection.range().sorted();
17829                let buffer_start_row = range.start.row;
17830
17831                if range.start.row != range.end.row {
17832                    let mut found = false;
17833                    let mut row = range.start.row;
17834                    while row <= range.end.row {
17835                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17836                        {
17837                            found = true;
17838                            row = crease.range().end.row + 1;
17839                            to_fold.push(crease);
17840                        } else {
17841                            row += 1
17842                        }
17843                    }
17844                    if found {
17845                        continue;
17846                    }
17847                }
17848
17849                for row in (0..=range.start.row).rev() {
17850                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17851                        && crease.range().end.row >= buffer_start_row
17852                    {
17853                        to_fold.push(crease);
17854                        if row <= range.start.row {
17855                            break;
17856                        }
17857                    }
17858                }
17859            }
17860
17861            self.fold_creases(to_fold, true, window, cx);
17862        } else {
17863            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17864            let buffer_ids = self
17865                .selections
17866                .disjoint_anchor_ranges()
17867                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17868                .collect::<HashSet<_>>();
17869            for buffer_id in buffer_ids {
17870                self.fold_buffer(buffer_id, cx);
17871            }
17872        }
17873    }
17874
17875    pub fn toggle_fold_all(
17876        &mut self,
17877        _: &actions::ToggleFoldAll,
17878        window: &mut Window,
17879        cx: &mut Context<Self>,
17880    ) {
17881        if self.buffer.read(cx).is_singleton() {
17882            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17883            let has_folds = display_map
17884                .folds_in_range(0..display_map.buffer_snapshot.len())
17885                .next()
17886                .is_some();
17887
17888            if has_folds {
17889                self.unfold_all(&actions::UnfoldAll, window, cx);
17890            } else {
17891                self.fold_all(&actions::FoldAll, window, cx);
17892            }
17893        } else {
17894            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17895            let should_unfold = buffer_ids
17896                .iter()
17897                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17898
17899            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17900                editor
17901                    .update_in(cx, |editor, _, cx| {
17902                        for buffer_id in buffer_ids {
17903                            if should_unfold {
17904                                editor.unfold_buffer(buffer_id, cx);
17905                            } else {
17906                                editor.fold_buffer(buffer_id, cx);
17907                            }
17908                        }
17909                    })
17910                    .ok();
17911            });
17912        }
17913    }
17914
17915    fn fold_at_level(
17916        &mut self,
17917        fold_at: &FoldAtLevel,
17918        window: &mut Window,
17919        cx: &mut Context<Self>,
17920    ) {
17921        if !self.buffer.read(cx).is_singleton() {
17922            return;
17923        }
17924
17925        let fold_at_level = fold_at.0;
17926        let snapshot = self.buffer.read(cx).snapshot(cx);
17927        let mut to_fold = Vec::new();
17928        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17929
17930        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17931            while start_row < end_row {
17932                match self
17933                    .snapshot(window, cx)
17934                    .crease_for_buffer_row(MultiBufferRow(start_row))
17935                {
17936                    Some(crease) => {
17937                        let nested_start_row = crease.range().start.row + 1;
17938                        let nested_end_row = crease.range().end.row;
17939
17940                        if current_level < fold_at_level {
17941                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17942                        } else if current_level == fold_at_level {
17943                            to_fold.push(crease);
17944                        }
17945
17946                        start_row = nested_end_row + 1;
17947                    }
17948                    None => start_row += 1,
17949                }
17950            }
17951        }
17952
17953        self.fold_creases(to_fold, true, window, cx);
17954    }
17955
17956    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17957        if self.buffer.read(cx).is_singleton() {
17958            let mut fold_ranges = Vec::new();
17959            let snapshot = self.buffer.read(cx).snapshot(cx);
17960
17961            for row in 0..snapshot.max_row().0 {
17962                if let Some(foldable_range) = self
17963                    .snapshot(window, cx)
17964                    .crease_for_buffer_row(MultiBufferRow(row))
17965                {
17966                    fold_ranges.push(foldable_range);
17967                }
17968            }
17969
17970            self.fold_creases(fold_ranges, true, window, cx);
17971        } else {
17972            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17973                editor
17974                    .update_in(cx, |editor, _, cx| {
17975                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17976                            editor.fold_buffer(buffer_id, cx);
17977                        }
17978                    })
17979                    .ok();
17980            });
17981        }
17982    }
17983
17984    pub fn fold_function_bodies(
17985        &mut self,
17986        _: &actions::FoldFunctionBodies,
17987        window: &mut Window,
17988        cx: &mut Context<Self>,
17989    ) {
17990        let snapshot = self.buffer.read(cx).snapshot(cx);
17991
17992        let ranges = snapshot
17993            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17994            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17995            .collect::<Vec<_>>();
17996
17997        let creases = ranges
17998            .into_iter()
17999            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18000            .collect();
18001
18002        self.fold_creases(creases, true, window, cx);
18003    }
18004
18005    pub fn fold_recursive(
18006        &mut self,
18007        _: &actions::FoldRecursive,
18008        window: &mut Window,
18009        cx: &mut Context<Self>,
18010    ) {
18011        let mut to_fold = Vec::new();
18012        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18013        let selections = self.selections.all_adjusted(cx);
18014
18015        for selection in selections {
18016            let range = selection.range().sorted();
18017            let buffer_start_row = range.start.row;
18018
18019            if range.start.row != range.end.row {
18020                let mut found = false;
18021                for row in range.start.row..=range.end.row {
18022                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18023                        found = true;
18024                        to_fold.push(crease);
18025                    }
18026                }
18027                if found {
18028                    continue;
18029                }
18030            }
18031
18032            for row in (0..=range.start.row).rev() {
18033                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18034                    if crease.range().end.row >= buffer_start_row {
18035                        to_fold.push(crease);
18036                    } else {
18037                        break;
18038                    }
18039                }
18040            }
18041        }
18042
18043        self.fold_creases(to_fold, true, window, cx);
18044    }
18045
18046    pub fn fold_at(
18047        &mut self,
18048        buffer_row: MultiBufferRow,
18049        window: &mut Window,
18050        cx: &mut Context<Self>,
18051    ) {
18052        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18053
18054        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18055            let autoscroll = self
18056                .selections
18057                .all::<Point>(cx)
18058                .iter()
18059                .any(|selection| crease.range().overlaps(&selection.range()));
18060
18061            self.fold_creases(vec![crease], autoscroll, window, cx);
18062        }
18063    }
18064
18065    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18066        if self.is_singleton(cx) {
18067            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18068            let buffer = &display_map.buffer_snapshot;
18069            let selections = self.selections.all::<Point>(cx);
18070            let ranges = selections
18071                .iter()
18072                .map(|s| {
18073                    let range = s.display_range(&display_map).sorted();
18074                    let mut start = range.start.to_point(&display_map);
18075                    let mut end = range.end.to_point(&display_map);
18076                    start.column = 0;
18077                    end.column = buffer.line_len(MultiBufferRow(end.row));
18078                    start..end
18079                })
18080                .collect::<Vec<_>>();
18081
18082            self.unfold_ranges(&ranges, true, true, cx);
18083        } else {
18084            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18085            let buffer_ids = self
18086                .selections
18087                .disjoint_anchor_ranges()
18088                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18089                .collect::<HashSet<_>>();
18090            for buffer_id in buffer_ids {
18091                self.unfold_buffer(buffer_id, cx);
18092            }
18093        }
18094    }
18095
18096    pub fn unfold_recursive(
18097        &mut self,
18098        _: &UnfoldRecursive,
18099        _window: &mut Window,
18100        cx: &mut Context<Self>,
18101    ) {
18102        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18103        let selections = self.selections.all::<Point>(cx);
18104        let ranges = selections
18105            .iter()
18106            .map(|s| {
18107                let mut range = s.display_range(&display_map).sorted();
18108                *range.start.column_mut() = 0;
18109                *range.end.column_mut() = display_map.line_len(range.end.row());
18110                let start = range.start.to_point(&display_map);
18111                let end = range.end.to_point(&display_map);
18112                start..end
18113            })
18114            .collect::<Vec<_>>();
18115
18116        self.unfold_ranges(&ranges, true, true, cx);
18117    }
18118
18119    pub fn unfold_at(
18120        &mut self,
18121        buffer_row: MultiBufferRow,
18122        _window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18126
18127        let intersection_range = Point::new(buffer_row.0, 0)
18128            ..Point::new(
18129                buffer_row.0,
18130                display_map.buffer_snapshot.line_len(buffer_row),
18131            );
18132
18133        let autoscroll = self
18134            .selections
18135            .all::<Point>(cx)
18136            .iter()
18137            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18138
18139        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18140    }
18141
18142    pub fn unfold_all(
18143        &mut self,
18144        _: &actions::UnfoldAll,
18145        _window: &mut Window,
18146        cx: &mut Context<Self>,
18147    ) {
18148        if self.buffer.read(cx).is_singleton() {
18149            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18150            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18151        } else {
18152            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18153                editor
18154                    .update(cx, |editor, cx| {
18155                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18156                            editor.unfold_buffer(buffer_id, cx);
18157                        }
18158                    })
18159                    .ok();
18160            });
18161        }
18162    }
18163
18164    pub fn fold_selected_ranges(
18165        &mut self,
18166        _: &FoldSelectedRanges,
18167        window: &mut Window,
18168        cx: &mut Context<Self>,
18169    ) {
18170        let selections = self.selections.all_adjusted(cx);
18171        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18172        let ranges = selections
18173            .into_iter()
18174            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18175            .collect::<Vec<_>>();
18176        self.fold_creases(ranges, true, window, cx);
18177    }
18178
18179    pub fn fold_ranges<T: ToOffset + Clone>(
18180        &mut self,
18181        ranges: Vec<Range<T>>,
18182        auto_scroll: bool,
18183        window: &mut Window,
18184        cx: &mut Context<Self>,
18185    ) {
18186        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18187        let ranges = ranges
18188            .into_iter()
18189            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18190            .collect::<Vec<_>>();
18191        self.fold_creases(ranges, auto_scroll, window, cx);
18192    }
18193
18194    pub fn fold_creases<T: ToOffset + Clone>(
18195        &mut self,
18196        creases: Vec<Crease<T>>,
18197        auto_scroll: bool,
18198        _window: &mut Window,
18199        cx: &mut Context<Self>,
18200    ) {
18201        if creases.is_empty() {
18202            return;
18203        }
18204
18205        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18206
18207        if auto_scroll {
18208            self.request_autoscroll(Autoscroll::fit(), cx);
18209        }
18210
18211        cx.notify();
18212
18213        self.scrollbar_marker_state.dirty = true;
18214        self.folds_did_change(cx);
18215    }
18216
18217    /// Removes any folds whose ranges intersect any of the given ranges.
18218    pub fn unfold_ranges<T: ToOffset + Clone>(
18219        &mut self,
18220        ranges: &[Range<T>],
18221        inclusive: bool,
18222        auto_scroll: bool,
18223        cx: &mut Context<Self>,
18224    ) {
18225        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18226            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18227        });
18228        self.folds_did_change(cx);
18229    }
18230
18231    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18232        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18233            return;
18234        }
18235        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18236        self.display_map.update(cx, |display_map, cx| {
18237            display_map.fold_buffers([buffer_id], cx)
18238        });
18239        cx.emit(EditorEvent::BufferFoldToggled {
18240            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18241            folded: true,
18242        });
18243        cx.notify();
18244    }
18245
18246    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18247        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18248            return;
18249        }
18250        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18251        self.display_map.update(cx, |display_map, cx| {
18252            display_map.unfold_buffers([buffer_id], cx);
18253        });
18254        cx.emit(EditorEvent::BufferFoldToggled {
18255            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18256            folded: false,
18257        });
18258        cx.notify();
18259    }
18260
18261    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18262        self.display_map.read(cx).is_buffer_folded(buffer)
18263    }
18264
18265    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18266        self.display_map.read(cx).folded_buffers()
18267    }
18268
18269    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18270        self.display_map.update(cx, |display_map, cx| {
18271            display_map.disable_header_for_buffer(buffer_id, cx);
18272        });
18273        cx.notify();
18274    }
18275
18276    /// Removes any folds with the given ranges.
18277    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18278        &mut self,
18279        ranges: &[Range<T>],
18280        type_id: TypeId,
18281        auto_scroll: bool,
18282        cx: &mut Context<Self>,
18283    ) {
18284        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18285            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18286        });
18287        self.folds_did_change(cx);
18288    }
18289
18290    fn remove_folds_with<T: ToOffset + Clone>(
18291        &mut self,
18292        ranges: &[Range<T>],
18293        auto_scroll: bool,
18294        cx: &mut Context<Self>,
18295        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18296    ) {
18297        if ranges.is_empty() {
18298            return;
18299        }
18300
18301        let mut buffers_affected = HashSet::default();
18302        let multi_buffer = self.buffer().read(cx);
18303        for range in ranges {
18304            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18305                buffers_affected.insert(buffer.read(cx).remote_id());
18306            };
18307        }
18308
18309        self.display_map.update(cx, update);
18310
18311        if auto_scroll {
18312            self.request_autoscroll(Autoscroll::fit(), cx);
18313        }
18314
18315        cx.notify();
18316        self.scrollbar_marker_state.dirty = true;
18317        self.active_indent_guides_state.dirty = true;
18318    }
18319
18320    pub fn update_renderer_widths(
18321        &mut self,
18322        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18323        cx: &mut Context<Self>,
18324    ) -> bool {
18325        self.display_map
18326            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18327    }
18328
18329    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18330        self.display_map.read(cx).fold_placeholder.clone()
18331    }
18332
18333    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18334        self.buffer.update(cx, |buffer, cx| {
18335            buffer.set_all_diff_hunks_expanded(cx);
18336        });
18337    }
18338
18339    pub fn expand_all_diff_hunks(
18340        &mut self,
18341        _: &ExpandAllDiffHunks,
18342        _window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        self.buffer.update(cx, |buffer, cx| {
18346            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18347        });
18348    }
18349
18350    pub fn toggle_selected_diff_hunks(
18351        &mut self,
18352        _: &ToggleSelectedDiffHunks,
18353        _window: &mut Window,
18354        cx: &mut Context<Self>,
18355    ) {
18356        let ranges: Vec<_> = self
18357            .selections
18358            .disjoint_anchors()
18359            .iter()
18360            .map(|s| s.range())
18361            .collect();
18362        self.toggle_diff_hunks_in_ranges(ranges, cx);
18363    }
18364
18365    pub fn diff_hunks_in_ranges<'a>(
18366        &'a self,
18367        ranges: &'a [Range<Anchor>],
18368        buffer: &'a MultiBufferSnapshot,
18369    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18370        ranges.iter().flat_map(move |range| {
18371            let end_excerpt_id = range.end.excerpt_id;
18372            let range = range.to_point(buffer);
18373            let mut peek_end = range.end;
18374            if range.end.row < buffer.max_row().0 {
18375                peek_end = Point::new(range.end.row + 1, 0);
18376            }
18377            buffer
18378                .diff_hunks_in_range(range.start..peek_end)
18379                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18380        })
18381    }
18382
18383    pub fn has_stageable_diff_hunks_in_ranges(
18384        &self,
18385        ranges: &[Range<Anchor>],
18386        snapshot: &MultiBufferSnapshot,
18387    ) -> bool {
18388        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18389        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18390    }
18391
18392    pub fn toggle_staged_selected_diff_hunks(
18393        &mut self,
18394        _: &::git::ToggleStaged,
18395        _: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) {
18398        let snapshot = self.buffer.read(cx).snapshot(cx);
18399        let ranges: Vec<_> = self
18400            .selections
18401            .disjoint_anchors()
18402            .iter()
18403            .map(|s| s.range())
18404            .collect();
18405        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18406        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18407    }
18408
18409    pub fn set_render_diff_hunk_controls(
18410        &mut self,
18411        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18412        cx: &mut Context<Self>,
18413    ) {
18414        self.render_diff_hunk_controls = render_diff_hunk_controls;
18415        cx.notify();
18416    }
18417
18418    pub fn stage_and_next(
18419        &mut self,
18420        _: &::git::StageAndNext,
18421        window: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) {
18424        self.do_stage_or_unstage_and_next(true, window, cx);
18425    }
18426
18427    pub fn unstage_and_next(
18428        &mut self,
18429        _: &::git::UnstageAndNext,
18430        window: &mut Window,
18431        cx: &mut Context<Self>,
18432    ) {
18433        self.do_stage_or_unstage_and_next(false, window, cx);
18434    }
18435
18436    pub fn stage_or_unstage_diff_hunks(
18437        &mut self,
18438        stage: bool,
18439        ranges: Vec<Range<Anchor>>,
18440        cx: &mut Context<Self>,
18441    ) {
18442        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18443        cx.spawn(async move |this, cx| {
18444            task.await?;
18445            this.update(cx, |this, cx| {
18446                let snapshot = this.buffer.read(cx).snapshot(cx);
18447                let chunk_by = this
18448                    .diff_hunks_in_ranges(&ranges, &snapshot)
18449                    .chunk_by(|hunk| hunk.buffer_id);
18450                for (buffer_id, hunks) in &chunk_by {
18451                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18452                }
18453            })
18454        })
18455        .detach_and_log_err(cx);
18456    }
18457
18458    fn save_buffers_for_ranges_if_needed(
18459        &mut self,
18460        ranges: &[Range<Anchor>],
18461        cx: &mut Context<Editor>,
18462    ) -> Task<Result<()>> {
18463        let multibuffer = self.buffer.read(cx);
18464        let snapshot = multibuffer.read(cx);
18465        let buffer_ids: HashSet<_> = ranges
18466            .iter()
18467            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18468            .collect();
18469        drop(snapshot);
18470
18471        let mut buffers = HashSet::default();
18472        for buffer_id in buffer_ids {
18473            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18474                let buffer = buffer_entity.read(cx);
18475                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18476                {
18477                    buffers.insert(buffer_entity);
18478                }
18479            }
18480        }
18481
18482        if let Some(project) = &self.project {
18483            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18484        } else {
18485            Task::ready(Ok(()))
18486        }
18487    }
18488
18489    fn do_stage_or_unstage_and_next(
18490        &mut self,
18491        stage: bool,
18492        window: &mut Window,
18493        cx: &mut Context<Self>,
18494    ) {
18495        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18496
18497        if ranges.iter().any(|range| range.start != range.end) {
18498            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18499            return;
18500        }
18501
18502        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18503        let snapshot = self.snapshot(window, cx);
18504        let position = self.selections.newest::<Point>(cx).head();
18505        let mut row = snapshot
18506            .buffer_snapshot
18507            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18508            .find(|hunk| hunk.row_range.start.0 > position.row)
18509            .map(|hunk| hunk.row_range.start);
18510
18511        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18512        // Outside of the project diff editor, wrap around to the beginning.
18513        if !all_diff_hunks_expanded {
18514            row = row.or_else(|| {
18515                snapshot
18516                    .buffer_snapshot
18517                    .diff_hunks_in_range(Point::zero()..position)
18518                    .find(|hunk| hunk.row_range.end.0 < position.row)
18519                    .map(|hunk| hunk.row_range.start)
18520            });
18521        }
18522
18523        if let Some(row) = row {
18524            let destination = Point::new(row.0, 0);
18525            let autoscroll = Autoscroll::center();
18526
18527            self.unfold_ranges(&[destination..destination], false, false, cx);
18528            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18529                s.select_ranges([destination..destination]);
18530            });
18531        }
18532    }
18533
18534    fn do_stage_or_unstage(
18535        &self,
18536        stage: bool,
18537        buffer_id: BufferId,
18538        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18539        cx: &mut App,
18540    ) -> Option<()> {
18541        let project = self.project()?;
18542        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18543        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18544        let buffer_snapshot = buffer.read(cx).snapshot();
18545        let file_exists = buffer_snapshot
18546            .file()
18547            .is_some_and(|file| file.disk_state().exists());
18548        diff.update(cx, |diff, cx| {
18549            diff.stage_or_unstage_hunks(
18550                stage,
18551                &hunks
18552                    .map(|hunk| buffer_diff::DiffHunk {
18553                        buffer_range: hunk.buffer_range,
18554                        diff_base_byte_range: hunk.diff_base_byte_range,
18555                        secondary_status: hunk.secondary_status,
18556                        range: Point::zero()..Point::zero(), // unused
18557                    })
18558                    .collect::<Vec<_>>(),
18559                &buffer_snapshot,
18560                file_exists,
18561                cx,
18562            )
18563        });
18564        None
18565    }
18566
18567    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18568        let ranges: Vec<_> = self
18569            .selections
18570            .disjoint_anchors()
18571            .iter()
18572            .map(|s| s.range())
18573            .collect();
18574        self.buffer
18575            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18576    }
18577
18578    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18579        self.buffer.update(cx, |buffer, cx| {
18580            let ranges = vec![Anchor::min()..Anchor::max()];
18581            if !buffer.all_diff_hunks_expanded()
18582                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18583            {
18584                buffer.collapse_diff_hunks(ranges, cx);
18585                true
18586            } else {
18587                false
18588            }
18589        })
18590    }
18591
18592    fn toggle_diff_hunks_in_ranges(
18593        &mut self,
18594        ranges: Vec<Range<Anchor>>,
18595        cx: &mut Context<Editor>,
18596    ) {
18597        self.buffer.update(cx, |buffer, cx| {
18598            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18599            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18600        })
18601    }
18602
18603    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18604        self.buffer.update(cx, |buffer, cx| {
18605            let snapshot = buffer.snapshot(cx);
18606            let excerpt_id = range.end.excerpt_id;
18607            let point_range = range.to_point(&snapshot);
18608            let expand = !buffer.single_hunk_is_expanded(range, cx);
18609            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18610        })
18611    }
18612
18613    pub(crate) fn apply_all_diff_hunks(
18614        &mut self,
18615        _: &ApplyAllDiffHunks,
18616        window: &mut Window,
18617        cx: &mut Context<Self>,
18618    ) {
18619        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18620
18621        let buffers = self.buffer.read(cx).all_buffers();
18622        for branch_buffer in buffers {
18623            branch_buffer.update(cx, |branch_buffer, cx| {
18624                branch_buffer.merge_into_base(Vec::new(), cx);
18625            });
18626        }
18627
18628        if let Some(project) = self.project.clone() {
18629            self.save(
18630                SaveOptions {
18631                    format: true,
18632                    autosave: false,
18633                },
18634                project,
18635                window,
18636                cx,
18637            )
18638            .detach_and_log_err(cx);
18639        }
18640    }
18641
18642    pub(crate) fn apply_selected_diff_hunks(
18643        &mut self,
18644        _: &ApplyDiffHunk,
18645        window: &mut Window,
18646        cx: &mut Context<Self>,
18647    ) {
18648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18649        let snapshot = self.snapshot(window, cx);
18650        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18651        let mut ranges_by_buffer = HashMap::default();
18652        self.transact(window, cx, |editor, _window, cx| {
18653            for hunk in hunks {
18654                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18655                    ranges_by_buffer
18656                        .entry(buffer.clone())
18657                        .or_insert_with(Vec::new)
18658                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18659                }
18660            }
18661
18662            for (buffer, ranges) in ranges_by_buffer {
18663                buffer.update(cx, |buffer, cx| {
18664                    buffer.merge_into_base(ranges, cx);
18665                });
18666            }
18667        });
18668
18669        if let Some(project) = self.project.clone() {
18670            self.save(
18671                SaveOptions {
18672                    format: true,
18673                    autosave: false,
18674                },
18675                project,
18676                window,
18677                cx,
18678            )
18679            .detach_and_log_err(cx);
18680        }
18681    }
18682
18683    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18684        if hovered != self.gutter_hovered {
18685            self.gutter_hovered = hovered;
18686            cx.notify();
18687        }
18688    }
18689
18690    pub fn insert_blocks(
18691        &mut self,
18692        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18693        autoscroll: Option<Autoscroll>,
18694        cx: &mut Context<Self>,
18695    ) -> Vec<CustomBlockId> {
18696        let blocks = self
18697            .display_map
18698            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18699        if let Some(autoscroll) = autoscroll {
18700            self.request_autoscroll(autoscroll, cx);
18701        }
18702        cx.notify();
18703        blocks
18704    }
18705
18706    pub fn resize_blocks(
18707        &mut self,
18708        heights: HashMap<CustomBlockId, u32>,
18709        autoscroll: Option<Autoscroll>,
18710        cx: &mut Context<Self>,
18711    ) {
18712        self.display_map
18713            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18714        if let Some(autoscroll) = autoscroll {
18715            self.request_autoscroll(autoscroll, cx);
18716        }
18717        cx.notify();
18718    }
18719
18720    pub fn replace_blocks(
18721        &mut self,
18722        renderers: HashMap<CustomBlockId, RenderBlock>,
18723        autoscroll: Option<Autoscroll>,
18724        cx: &mut Context<Self>,
18725    ) {
18726        self.display_map
18727            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18728        if let Some(autoscroll) = autoscroll {
18729            self.request_autoscroll(autoscroll, cx);
18730        }
18731        cx.notify();
18732    }
18733
18734    pub fn remove_blocks(
18735        &mut self,
18736        block_ids: HashSet<CustomBlockId>,
18737        autoscroll: Option<Autoscroll>,
18738        cx: &mut Context<Self>,
18739    ) {
18740        self.display_map.update(cx, |display_map, cx| {
18741            display_map.remove_blocks(block_ids, cx)
18742        });
18743        if let Some(autoscroll) = autoscroll {
18744            self.request_autoscroll(autoscroll, cx);
18745        }
18746        cx.notify();
18747    }
18748
18749    pub fn row_for_block(
18750        &self,
18751        block_id: CustomBlockId,
18752        cx: &mut Context<Self>,
18753    ) -> Option<DisplayRow> {
18754        self.display_map
18755            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18756    }
18757
18758    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18759        self.focused_block = Some(focused_block);
18760    }
18761
18762    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18763        self.focused_block.take()
18764    }
18765
18766    pub fn insert_creases(
18767        &mut self,
18768        creases: impl IntoIterator<Item = Crease<Anchor>>,
18769        cx: &mut Context<Self>,
18770    ) -> Vec<CreaseId> {
18771        self.display_map
18772            .update(cx, |map, cx| map.insert_creases(creases, cx))
18773    }
18774
18775    pub fn remove_creases(
18776        &mut self,
18777        ids: impl IntoIterator<Item = CreaseId>,
18778        cx: &mut Context<Self>,
18779    ) -> Vec<(CreaseId, Range<Anchor>)> {
18780        self.display_map
18781            .update(cx, |map, cx| map.remove_creases(ids, cx))
18782    }
18783
18784    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18785        self.display_map
18786            .update(cx, |map, cx| map.snapshot(cx))
18787            .longest_row()
18788    }
18789
18790    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18791        self.display_map
18792            .update(cx, |map, cx| map.snapshot(cx))
18793            .max_point()
18794    }
18795
18796    pub fn text(&self, cx: &App) -> String {
18797        self.buffer.read(cx).read(cx).text()
18798    }
18799
18800    pub fn is_empty(&self, cx: &App) -> bool {
18801        self.buffer.read(cx).read(cx).is_empty()
18802    }
18803
18804    pub fn text_option(&self, cx: &App) -> Option<String> {
18805        let text = self.text(cx);
18806        let text = text.trim();
18807
18808        if text.is_empty() {
18809            return None;
18810        }
18811
18812        Some(text.to_string())
18813    }
18814
18815    pub fn set_text(
18816        &mut self,
18817        text: impl Into<Arc<str>>,
18818        window: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        self.transact(window, cx, |this, _, cx| {
18822            this.buffer
18823                .read(cx)
18824                .as_singleton()
18825                .expect("you can only call set_text on editors for singleton buffers")
18826                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18827        });
18828    }
18829
18830    pub fn display_text(&self, cx: &mut App) -> String {
18831        self.display_map
18832            .update(cx, |map, cx| map.snapshot(cx))
18833            .text()
18834    }
18835
18836    fn create_minimap(
18837        &self,
18838        minimap_settings: MinimapSettings,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) -> Option<Entity<Self>> {
18842        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18843            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18844    }
18845
18846    fn initialize_new_minimap(
18847        &self,
18848        minimap_settings: MinimapSettings,
18849        window: &mut Window,
18850        cx: &mut Context<Self>,
18851    ) -> Entity<Self> {
18852        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18853
18854        let mut minimap = Editor::new_internal(
18855            EditorMode::Minimap {
18856                parent: cx.weak_entity(),
18857            },
18858            self.buffer.clone(),
18859            None,
18860            Some(self.display_map.clone()),
18861            window,
18862            cx,
18863        );
18864        minimap.scroll_manager.clone_state(&self.scroll_manager);
18865        minimap.set_text_style_refinement(TextStyleRefinement {
18866            font_size: Some(MINIMAP_FONT_SIZE),
18867            font_weight: Some(MINIMAP_FONT_WEIGHT),
18868            ..Default::default()
18869        });
18870        minimap.update_minimap_configuration(minimap_settings, cx);
18871        cx.new(|_| minimap)
18872    }
18873
18874    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18875        let current_line_highlight = minimap_settings
18876            .current_line_highlight
18877            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18878        self.set_current_line_highlight(Some(current_line_highlight));
18879    }
18880
18881    pub fn minimap(&self) -> Option<&Entity<Self>> {
18882        self.minimap
18883            .as_ref()
18884            .filter(|_| self.minimap_visibility.visible())
18885    }
18886
18887    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18888        let mut wrap_guides = smallvec![];
18889
18890        if self.show_wrap_guides == Some(false) {
18891            return wrap_guides;
18892        }
18893
18894        let settings = self.buffer.read(cx).language_settings(cx);
18895        if settings.show_wrap_guides {
18896            match self.soft_wrap_mode(cx) {
18897                SoftWrap::Column(soft_wrap) => {
18898                    wrap_guides.push((soft_wrap as usize, true));
18899                }
18900                SoftWrap::Bounded(soft_wrap) => {
18901                    wrap_guides.push((soft_wrap as usize, true));
18902                }
18903                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18904            }
18905            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18906        }
18907
18908        wrap_guides
18909    }
18910
18911    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18912        let settings = self.buffer.read(cx).language_settings(cx);
18913        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18914        match mode {
18915            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18916                SoftWrap::None
18917            }
18918            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18919            language_settings::SoftWrap::PreferredLineLength => {
18920                SoftWrap::Column(settings.preferred_line_length)
18921            }
18922            language_settings::SoftWrap::Bounded => {
18923                SoftWrap::Bounded(settings.preferred_line_length)
18924            }
18925        }
18926    }
18927
18928    pub fn set_soft_wrap_mode(
18929        &mut self,
18930        mode: language_settings::SoftWrap,
18931
18932        cx: &mut Context<Self>,
18933    ) {
18934        self.soft_wrap_mode_override = Some(mode);
18935        cx.notify();
18936    }
18937
18938    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18939        self.hard_wrap = hard_wrap;
18940        cx.notify();
18941    }
18942
18943    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18944        self.text_style_refinement = Some(style);
18945    }
18946
18947    /// called by the Element so we know what style we were most recently rendered with.
18948    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18949        // We intentionally do not inform the display map about the minimap style
18950        // so that wrapping is not recalculated and stays consistent for the editor
18951        // and its linked minimap.
18952        if !self.mode.is_minimap() {
18953            let font = style.text.font();
18954            let font_size = style.text.font_size.to_pixels(window.rem_size());
18955            let display_map = self
18956                .placeholder_display_map
18957                .as_ref()
18958                .filter(|_| self.is_empty(cx))
18959                .unwrap_or(&self.display_map);
18960
18961            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18962        }
18963        self.style = Some(style);
18964    }
18965
18966    pub fn style(&self) -> Option<&EditorStyle> {
18967        self.style.as_ref()
18968    }
18969
18970    // Called by the element. This method is not designed to be called outside of the editor
18971    // element's layout code because it does not notify when rewrapping is computed synchronously.
18972    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18973        if self.is_empty(cx) {
18974            self.placeholder_display_map
18975                .as_ref()
18976                .map_or(false, |display_map| {
18977                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18978                })
18979        } else {
18980            self.display_map
18981                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18982        }
18983    }
18984
18985    pub fn set_soft_wrap(&mut self) {
18986        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18987    }
18988
18989    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18990        if self.soft_wrap_mode_override.is_some() {
18991            self.soft_wrap_mode_override.take();
18992        } else {
18993            let soft_wrap = match self.soft_wrap_mode(cx) {
18994                SoftWrap::GitDiff => return,
18995                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18996                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18997                    language_settings::SoftWrap::None
18998                }
18999            };
19000            self.soft_wrap_mode_override = Some(soft_wrap);
19001        }
19002        cx.notify();
19003    }
19004
19005    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19006        let Some(workspace) = self.workspace() else {
19007            return;
19008        };
19009        let fs = workspace.read(cx).app_state().fs.clone();
19010        let current_show = TabBarSettings::get_global(cx).show;
19011        update_settings_file(fs, cx, move |setting, _| {
19012            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19013        });
19014    }
19015
19016    pub fn toggle_indent_guides(
19017        &mut self,
19018        _: &ToggleIndentGuides,
19019        _: &mut Window,
19020        cx: &mut Context<Self>,
19021    ) {
19022        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19023            self.buffer
19024                .read(cx)
19025                .language_settings(cx)
19026                .indent_guides
19027                .enabled
19028        });
19029        self.show_indent_guides = Some(!currently_enabled);
19030        cx.notify();
19031    }
19032
19033    fn should_show_indent_guides(&self) -> Option<bool> {
19034        self.show_indent_guides
19035    }
19036
19037    pub fn toggle_line_numbers(
19038        &mut self,
19039        _: &ToggleLineNumbers,
19040        _: &mut Window,
19041        cx: &mut Context<Self>,
19042    ) {
19043        let mut editor_settings = EditorSettings::get_global(cx).clone();
19044        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19045        EditorSettings::override_global(editor_settings, cx);
19046    }
19047
19048    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19049        if let Some(show_line_numbers) = self.show_line_numbers {
19050            return show_line_numbers;
19051        }
19052        EditorSettings::get_global(cx).gutter.line_numbers
19053    }
19054
19055    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19056        self.use_relative_line_numbers
19057            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19058    }
19059
19060    pub fn toggle_relative_line_numbers(
19061        &mut self,
19062        _: &ToggleRelativeLineNumbers,
19063        _: &mut Window,
19064        cx: &mut Context<Self>,
19065    ) {
19066        let is_relative = self.should_use_relative_line_numbers(cx);
19067        self.set_relative_line_number(Some(!is_relative), cx)
19068    }
19069
19070    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19071        self.use_relative_line_numbers = is_relative;
19072        cx.notify();
19073    }
19074
19075    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19076        self.show_gutter = show_gutter;
19077        cx.notify();
19078    }
19079
19080    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19081        self.show_scrollbars = ScrollbarAxes {
19082            horizontal: show,
19083            vertical: show,
19084        };
19085        cx.notify();
19086    }
19087
19088    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19089        self.show_scrollbars.vertical = show;
19090        cx.notify();
19091    }
19092
19093    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19094        self.show_scrollbars.horizontal = show;
19095        cx.notify();
19096    }
19097
19098    pub fn set_minimap_visibility(
19099        &mut self,
19100        minimap_visibility: MinimapVisibility,
19101        window: &mut Window,
19102        cx: &mut Context<Self>,
19103    ) {
19104        if self.minimap_visibility != minimap_visibility {
19105            if minimap_visibility.visible() && self.minimap.is_none() {
19106                let minimap_settings = EditorSettings::get_global(cx).minimap;
19107                self.minimap =
19108                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19109            }
19110            self.minimap_visibility = minimap_visibility;
19111            cx.notify();
19112        }
19113    }
19114
19115    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19116        self.set_show_scrollbars(false, cx);
19117        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19118    }
19119
19120    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19121        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19122    }
19123
19124    /// Normally the text in full mode and auto height editors is padded on the
19125    /// left side by roughly half a character width for improved hit testing.
19126    ///
19127    /// Use this method to disable this for cases where this is not wanted (e.g.
19128    /// if you want to align the editor text with some other text above or below)
19129    /// or if you want to add this padding to single-line editors.
19130    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19131        self.offset_content = offset_content;
19132        cx.notify();
19133    }
19134
19135    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19136        self.show_line_numbers = Some(show_line_numbers);
19137        cx.notify();
19138    }
19139
19140    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19141        self.disable_expand_excerpt_buttons = true;
19142        cx.notify();
19143    }
19144
19145    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19146        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19147        cx.notify();
19148    }
19149
19150    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19151        self.show_code_actions = Some(show_code_actions);
19152        cx.notify();
19153    }
19154
19155    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19156        self.show_runnables = Some(show_runnables);
19157        cx.notify();
19158    }
19159
19160    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19161        self.show_breakpoints = Some(show_breakpoints);
19162        cx.notify();
19163    }
19164
19165    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19166        if self.display_map.read(cx).masked != masked {
19167            self.display_map.update(cx, |map, _| map.masked = masked);
19168        }
19169        cx.notify()
19170    }
19171
19172    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19173        self.show_wrap_guides = Some(show_wrap_guides);
19174        cx.notify();
19175    }
19176
19177    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19178        self.show_indent_guides = Some(show_indent_guides);
19179        cx.notify();
19180    }
19181
19182    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19183        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19184            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19185                && let Some(dir) = file.abs_path(cx).parent()
19186            {
19187                return Some(dir.to_owned());
19188            }
19189
19190            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19191                return Some(project_path.path.to_path_buf());
19192            }
19193        }
19194
19195        None
19196    }
19197
19198    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19199        self.active_excerpt(cx)?
19200            .1
19201            .read(cx)
19202            .file()
19203            .and_then(|f| f.as_local())
19204    }
19205
19206    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19207        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19208            let buffer = buffer.read(cx);
19209            if let Some(project_path) = buffer.project_path(cx) {
19210                let project = self.project()?.read(cx);
19211                project.absolute_path(&project_path, cx)
19212            } else {
19213                buffer
19214                    .file()
19215                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19216            }
19217        })
19218    }
19219
19220    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19221        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19222            let project_path = buffer.read(cx).project_path(cx)?;
19223            let project = self.project()?.read(cx);
19224            let entry = project.entry_for_path(&project_path, cx)?;
19225            let path = entry.path.to_path_buf();
19226            Some(path)
19227        })
19228    }
19229
19230    pub fn reveal_in_finder(
19231        &mut self,
19232        _: &RevealInFileManager,
19233        _window: &mut Window,
19234        cx: &mut Context<Self>,
19235    ) {
19236        if let Some(target) = self.target_file(cx) {
19237            cx.reveal_path(&target.abs_path(cx));
19238        }
19239    }
19240
19241    pub fn copy_path(
19242        &mut self,
19243        _: &zed_actions::workspace::CopyPath,
19244        _window: &mut Window,
19245        cx: &mut Context<Self>,
19246    ) {
19247        if let Some(path) = self.target_file_abs_path(cx)
19248            && let Some(path) = path.to_str()
19249        {
19250            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19251        }
19252    }
19253
19254    pub fn copy_relative_path(
19255        &mut self,
19256        _: &zed_actions::workspace::CopyRelativePath,
19257        _window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) {
19260        if let Some(path) = self.target_file_path(cx)
19261            && let Some(path) = path.to_str()
19262        {
19263            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19264        }
19265    }
19266
19267    /// Returns the project path for the editor's buffer, if any buffer is
19268    /// opened in the editor.
19269    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19270        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19271            buffer.read(cx).project_path(cx)
19272        } else {
19273            None
19274        }
19275    }
19276
19277    // Returns true if the editor handled a go-to-line request
19278    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19279        maybe!({
19280            let breakpoint_store = self.breakpoint_store.as_ref()?;
19281
19282            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19283            else {
19284                self.clear_row_highlights::<ActiveDebugLine>();
19285                return None;
19286            };
19287
19288            let position = active_stack_frame.position;
19289            let buffer_id = position.buffer_id?;
19290            let snapshot = self
19291                .project
19292                .as_ref()?
19293                .read(cx)
19294                .buffer_for_id(buffer_id, cx)?
19295                .read(cx)
19296                .snapshot();
19297
19298            let mut handled = false;
19299            for (id, ExcerptRange { context, .. }) in
19300                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19301            {
19302                if context.start.cmp(&position, &snapshot).is_ge()
19303                    || context.end.cmp(&position, &snapshot).is_lt()
19304                {
19305                    continue;
19306                }
19307                let snapshot = self.buffer.read(cx).snapshot(cx);
19308                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19309
19310                handled = true;
19311                self.clear_row_highlights::<ActiveDebugLine>();
19312
19313                self.go_to_line::<ActiveDebugLine>(
19314                    multibuffer_anchor,
19315                    Some(cx.theme().colors().editor_debugger_active_line_background),
19316                    window,
19317                    cx,
19318                );
19319
19320                cx.notify();
19321            }
19322
19323            handled.then_some(())
19324        })
19325        .is_some()
19326    }
19327
19328    pub fn copy_file_name_without_extension(
19329        &mut self,
19330        _: &CopyFileNameWithoutExtension,
19331        _: &mut Window,
19332        cx: &mut Context<Self>,
19333    ) {
19334        if let Some(file) = self.target_file(cx)
19335            && let Some(file_stem) = file.path().file_stem()
19336            && let Some(name) = file_stem.to_str()
19337        {
19338            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19339        }
19340    }
19341
19342    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19343        if let Some(file) = self.target_file(cx)
19344            && let Some(file_name) = file.path().file_name()
19345            && let Some(name) = file_name.to_str()
19346        {
19347            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19348        }
19349    }
19350
19351    pub fn toggle_git_blame(
19352        &mut self,
19353        _: &::git::Blame,
19354        window: &mut Window,
19355        cx: &mut Context<Self>,
19356    ) {
19357        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19358
19359        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19360            self.start_git_blame(true, window, cx);
19361        }
19362
19363        cx.notify();
19364    }
19365
19366    pub fn toggle_git_blame_inline(
19367        &mut self,
19368        _: &ToggleGitBlameInline,
19369        window: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) {
19372        self.toggle_git_blame_inline_internal(true, window, cx);
19373        cx.notify();
19374    }
19375
19376    pub fn open_git_blame_commit(
19377        &mut self,
19378        _: &OpenGitBlameCommit,
19379        window: &mut Window,
19380        cx: &mut Context<Self>,
19381    ) {
19382        self.open_git_blame_commit_internal(window, cx);
19383    }
19384
19385    fn open_git_blame_commit_internal(
19386        &mut self,
19387        window: &mut Window,
19388        cx: &mut Context<Self>,
19389    ) -> Option<()> {
19390        let blame = self.blame.as_ref()?;
19391        let snapshot = self.snapshot(window, cx);
19392        let cursor = self.selections.newest::<Point>(cx).head();
19393        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19394        let (_, blame_entry) = blame
19395            .update(cx, |blame, cx| {
19396                blame
19397                    .blame_for_rows(
19398                        &[RowInfo {
19399                            buffer_id: Some(buffer.remote_id()),
19400                            buffer_row: Some(point.row),
19401                            ..Default::default()
19402                        }],
19403                        cx,
19404                    )
19405                    .next()
19406            })
19407            .flatten()?;
19408        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19409        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19410        let workspace = self.workspace()?.downgrade();
19411        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19412        None
19413    }
19414
19415    pub fn git_blame_inline_enabled(&self) -> bool {
19416        self.git_blame_inline_enabled
19417    }
19418
19419    pub fn toggle_selection_menu(
19420        &mut self,
19421        _: &ToggleSelectionMenu,
19422        _: &mut Window,
19423        cx: &mut Context<Self>,
19424    ) {
19425        self.show_selection_menu = self
19426            .show_selection_menu
19427            .map(|show_selections_menu| !show_selections_menu)
19428            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19429
19430        cx.notify();
19431    }
19432
19433    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19434        self.show_selection_menu
19435            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19436    }
19437
19438    fn start_git_blame(
19439        &mut self,
19440        user_triggered: bool,
19441        window: &mut Window,
19442        cx: &mut Context<Self>,
19443    ) {
19444        if let Some(project) = self.project() {
19445            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19446                && buffer.read(cx).file().is_none()
19447            {
19448                return;
19449            }
19450
19451            let focused = self.focus_handle(cx).contains_focused(window, cx);
19452
19453            let project = project.clone();
19454            let blame = cx
19455                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19456            self.blame_subscription =
19457                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19458            self.blame = Some(blame);
19459        }
19460    }
19461
19462    fn toggle_git_blame_inline_internal(
19463        &mut self,
19464        user_triggered: bool,
19465        window: &mut Window,
19466        cx: &mut Context<Self>,
19467    ) {
19468        if self.git_blame_inline_enabled {
19469            self.git_blame_inline_enabled = false;
19470            self.show_git_blame_inline = false;
19471            self.show_git_blame_inline_delay_task.take();
19472        } else {
19473            self.git_blame_inline_enabled = true;
19474            self.start_git_blame_inline(user_triggered, window, cx);
19475        }
19476
19477        cx.notify();
19478    }
19479
19480    fn start_git_blame_inline(
19481        &mut self,
19482        user_triggered: bool,
19483        window: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) {
19486        self.start_git_blame(user_triggered, window, cx);
19487
19488        if ProjectSettings::get_global(cx)
19489            .git
19490            .inline_blame_delay()
19491            .is_some()
19492        {
19493            self.start_inline_blame_timer(window, cx);
19494        } else {
19495            self.show_git_blame_inline = true
19496        }
19497    }
19498
19499    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19500        self.blame.as_ref()
19501    }
19502
19503    pub fn show_git_blame_gutter(&self) -> bool {
19504        self.show_git_blame_gutter
19505    }
19506
19507    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19508        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19509    }
19510
19511    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19512        self.show_git_blame_inline
19513            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19514            && !self.newest_selection_head_on_empty_line(cx)
19515            && self.has_blame_entries(cx)
19516    }
19517
19518    fn has_blame_entries(&self, cx: &App) -> bool {
19519        self.blame()
19520            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19521    }
19522
19523    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19524        let cursor_anchor = self.selections.newest_anchor().head();
19525
19526        let snapshot = self.buffer.read(cx).snapshot(cx);
19527        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19528
19529        snapshot.line_len(buffer_row) == 0
19530    }
19531
19532    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19533        let buffer_and_selection = maybe!({
19534            let selection = self.selections.newest::<Point>(cx);
19535            let selection_range = selection.range();
19536
19537            let multi_buffer = self.buffer().read(cx);
19538            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19539            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19540
19541            let (buffer, range, _) = if selection.reversed {
19542                buffer_ranges.first()
19543            } else {
19544                buffer_ranges.last()
19545            }?;
19546
19547            let selection = text::ToPoint::to_point(&range.start, buffer).row
19548                ..text::ToPoint::to_point(&range.end, buffer).row;
19549            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19550        });
19551
19552        let Some((buffer, selection)) = buffer_and_selection else {
19553            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19554        };
19555
19556        let Some(project) = self.project() else {
19557            return Task::ready(Err(anyhow!("editor does not have project")));
19558        };
19559
19560        project.update(cx, |project, cx| {
19561            project.get_permalink_to_line(&buffer, selection, cx)
19562        })
19563    }
19564
19565    pub fn copy_permalink_to_line(
19566        &mut self,
19567        _: &CopyPermalinkToLine,
19568        window: &mut Window,
19569        cx: &mut Context<Self>,
19570    ) {
19571        let permalink_task = self.get_permalink_to_line(cx);
19572        let workspace = self.workspace();
19573
19574        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19575            Ok(permalink) => {
19576                cx.update(|_, cx| {
19577                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19578                })
19579                .ok();
19580            }
19581            Err(err) => {
19582                let message = format!("Failed to copy permalink: {err}");
19583
19584                anyhow::Result::<()>::Err(err).log_err();
19585
19586                if let Some(workspace) = workspace {
19587                    workspace
19588                        .update_in(cx, |workspace, _, cx| {
19589                            struct CopyPermalinkToLine;
19590
19591                            workspace.show_toast(
19592                                Toast::new(
19593                                    NotificationId::unique::<CopyPermalinkToLine>(),
19594                                    message,
19595                                ),
19596                                cx,
19597                            )
19598                        })
19599                        .ok();
19600                }
19601            }
19602        })
19603        .detach();
19604    }
19605
19606    pub fn copy_file_location(
19607        &mut self,
19608        _: &CopyFileLocation,
19609        _: &mut Window,
19610        cx: &mut Context<Self>,
19611    ) {
19612        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19613        if let Some(file) = self.target_file(cx)
19614            && let Some(path) = file.path().to_str()
19615        {
19616            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19617        }
19618    }
19619
19620    pub fn open_permalink_to_line(
19621        &mut self,
19622        _: &OpenPermalinkToLine,
19623        window: &mut Window,
19624        cx: &mut Context<Self>,
19625    ) {
19626        let permalink_task = self.get_permalink_to_line(cx);
19627        let workspace = self.workspace();
19628
19629        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19630            Ok(permalink) => {
19631                cx.update(|_, cx| {
19632                    cx.open_url(permalink.as_ref());
19633                })
19634                .ok();
19635            }
19636            Err(err) => {
19637                let message = format!("Failed to open permalink: {err}");
19638
19639                anyhow::Result::<()>::Err(err).log_err();
19640
19641                if let Some(workspace) = workspace {
19642                    workspace
19643                        .update(cx, |workspace, cx| {
19644                            struct OpenPermalinkToLine;
19645
19646                            workspace.show_toast(
19647                                Toast::new(
19648                                    NotificationId::unique::<OpenPermalinkToLine>(),
19649                                    message,
19650                                ),
19651                                cx,
19652                            )
19653                        })
19654                        .ok();
19655                }
19656            }
19657        })
19658        .detach();
19659    }
19660
19661    pub fn insert_uuid_v4(
19662        &mut self,
19663        _: &InsertUuidV4,
19664        window: &mut Window,
19665        cx: &mut Context<Self>,
19666    ) {
19667        self.insert_uuid(UuidVersion::V4, window, cx);
19668    }
19669
19670    pub fn insert_uuid_v7(
19671        &mut self,
19672        _: &InsertUuidV7,
19673        window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        self.insert_uuid(UuidVersion::V7, window, cx);
19677    }
19678
19679    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19681        self.transact(window, cx, |this, window, cx| {
19682            let edits = this
19683                .selections
19684                .all::<Point>(cx)
19685                .into_iter()
19686                .map(|selection| {
19687                    let uuid = match version {
19688                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19689                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19690                    };
19691
19692                    (selection.range(), uuid.to_string())
19693                });
19694            this.edit(edits, cx);
19695            this.refresh_edit_prediction(true, false, window, cx);
19696        });
19697    }
19698
19699    pub fn open_selections_in_multibuffer(
19700        &mut self,
19701        _: &OpenSelectionsInMultibuffer,
19702        window: &mut Window,
19703        cx: &mut Context<Self>,
19704    ) {
19705        let multibuffer = self.buffer.read(cx);
19706
19707        let Some(buffer) = multibuffer.as_singleton() else {
19708            return;
19709        };
19710
19711        let Some(workspace) = self.workspace() else {
19712            return;
19713        };
19714
19715        let title = multibuffer.title(cx).to_string();
19716
19717        let locations = self
19718            .selections
19719            .all_anchors(cx)
19720            .iter()
19721            .map(|selection| Location {
19722                buffer: buffer.clone(),
19723                range: selection.start.text_anchor..selection.end.text_anchor,
19724            })
19725            .collect::<Vec<_>>();
19726
19727        cx.spawn_in(window, async move |_, cx| {
19728            workspace.update_in(cx, |workspace, window, cx| {
19729                Self::open_locations_in_multibuffer(
19730                    workspace,
19731                    locations,
19732                    format!("Selections for '{title}'"),
19733                    false,
19734                    MultibufferSelectionMode::All,
19735                    window,
19736                    cx,
19737                );
19738            })
19739        })
19740        .detach();
19741    }
19742
19743    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19744    /// last highlight added will be used.
19745    ///
19746    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19747    pub fn highlight_rows<T: 'static>(
19748        &mut self,
19749        range: Range<Anchor>,
19750        color: Hsla,
19751        options: RowHighlightOptions,
19752        cx: &mut Context<Self>,
19753    ) {
19754        let snapshot = self.buffer().read(cx).snapshot(cx);
19755        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19756        let ix = row_highlights.binary_search_by(|highlight| {
19757            Ordering::Equal
19758                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19759                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19760        });
19761
19762        if let Err(mut ix) = ix {
19763            let index = post_inc(&mut self.highlight_order);
19764
19765            // If this range intersects with the preceding highlight, then merge it with
19766            // the preceding highlight. Otherwise insert a new highlight.
19767            let mut merged = false;
19768            if ix > 0 {
19769                let prev_highlight = &mut row_highlights[ix - 1];
19770                if prev_highlight
19771                    .range
19772                    .end
19773                    .cmp(&range.start, &snapshot)
19774                    .is_ge()
19775                {
19776                    ix -= 1;
19777                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19778                        prev_highlight.range.end = range.end;
19779                    }
19780                    merged = true;
19781                    prev_highlight.index = index;
19782                    prev_highlight.color = color;
19783                    prev_highlight.options = options;
19784                }
19785            }
19786
19787            if !merged {
19788                row_highlights.insert(
19789                    ix,
19790                    RowHighlight {
19791                        range,
19792                        index,
19793                        color,
19794                        options,
19795                        type_id: TypeId::of::<T>(),
19796                    },
19797                );
19798            }
19799
19800            // If any of the following highlights intersect with this one, merge them.
19801            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19802                let highlight = &row_highlights[ix];
19803                if next_highlight
19804                    .range
19805                    .start
19806                    .cmp(&highlight.range.end, &snapshot)
19807                    .is_le()
19808                {
19809                    if next_highlight
19810                        .range
19811                        .end
19812                        .cmp(&highlight.range.end, &snapshot)
19813                        .is_gt()
19814                    {
19815                        row_highlights[ix].range.end = next_highlight.range.end;
19816                    }
19817                    row_highlights.remove(ix + 1);
19818                } else {
19819                    break;
19820                }
19821            }
19822        }
19823    }
19824
19825    /// Remove any highlighted row ranges of the given type that intersect the
19826    /// given ranges.
19827    pub fn remove_highlighted_rows<T: 'static>(
19828        &mut self,
19829        ranges_to_remove: Vec<Range<Anchor>>,
19830        cx: &mut Context<Self>,
19831    ) {
19832        let snapshot = self.buffer().read(cx).snapshot(cx);
19833        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19834        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19835        row_highlights.retain(|highlight| {
19836            while let Some(range_to_remove) = ranges_to_remove.peek() {
19837                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19838                    Ordering::Less | Ordering::Equal => {
19839                        ranges_to_remove.next();
19840                    }
19841                    Ordering::Greater => {
19842                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19843                            Ordering::Less | Ordering::Equal => {
19844                                return false;
19845                            }
19846                            Ordering::Greater => break,
19847                        }
19848                    }
19849                }
19850            }
19851
19852            true
19853        })
19854    }
19855
19856    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19857    pub fn clear_row_highlights<T: 'static>(&mut self) {
19858        self.highlighted_rows.remove(&TypeId::of::<T>());
19859    }
19860
19861    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19862    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19863        self.highlighted_rows
19864            .get(&TypeId::of::<T>())
19865            .map_or(&[] as &[_], |vec| vec.as_slice())
19866            .iter()
19867            .map(|highlight| (highlight.range.clone(), highlight.color))
19868    }
19869
19870    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19871    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19872    /// Allows to ignore certain kinds of highlights.
19873    pub fn highlighted_display_rows(
19874        &self,
19875        window: &mut Window,
19876        cx: &mut App,
19877    ) -> BTreeMap<DisplayRow, LineHighlight> {
19878        let snapshot = self.snapshot(window, cx);
19879        let mut used_highlight_orders = HashMap::default();
19880        self.highlighted_rows
19881            .iter()
19882            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19883            .fold(
19884                BTreeMap::<DisplayRow, LineHighlight>::new(),
19885                |mut unique_rows, highlight| {
19886                    let start = highlight.range.start.to_display_point(&snapshot);
19887                    let end = highlight.range.end.to_display_point(&snapshot);
19888                    let start_row = start.row().0;
19889                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19890                        && end.column() == 0
19891                    {
19892                        end.row().0.saturating_sub(1)
19893                    } else {
19894                        end.row().0
19895                    };
19896                    for row in start_row..=end_row {
19897                        let used_index =
19898                            used_highlight_orders.entry(row).or_insert(highlight.index);
19899                        if highlight.index >= *used_index {
19900                            *used_index = highlight.index;
19901                            unique_rows.insert(
19902                                DisplayRow(row),
19903                                LineHighlight {
19904                                    include_gutter: highlight.options.include_gutter,
19905                                    border: None,
19906                                    background: highlight.color.into(),
19907                                    type_id: Some(highlight.type_id),
19908                                },
19909                            );
19910                        }
19911                    }
19912                    unique_rows
19913                },
19914            )
19915    }
19916
19917    pub fn highlighted_display_row_for_autoscroll(
19918        &self,
19919        snapshot: &DisplaySnapshot,
19920    ) -> Option<DisplayRow> {
19921        self.highlighted_rows
19922            .values()
19923            .flat_map(|highlighted_rows| highlighted_rows.iter())
19924            .filter_map(|highlight| {
19925                if highlight.options.autoscroll {
19926                    Some(highlight.range.start.to_display_point(snapshot).row())
19927                } else {
19928                    None
19929                }
19930            })
19931            .min()
19932    }
19933
19934    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19935        self.highlight_background::<SearchWithinRange>(
19936            ranges,
19937            |colors| colors.colors().editor_document_highlight_read_background,
19938            cx,
19939        )
19940    }
19941
19942    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19943        self.breadcrumb_header = Some(new_header);
19944    }
19945
19946    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19947        self.clear_background_highlights::<SearchWithinRange>(cx);
19948    }
19949
19950    pub fn highlight_background<T: 'static>(
19951        &mut self,
19952        ranges: &[Range<Anchor>],
19953        color_fetcher: fn(&Theme) -> Hsla,
19954        cx: &mut Context<Self>,
19955    ) {
19956        self.background_highlights.insert(
19957            HighlightKey::Type(TypeId::of::<T>()),
19958            (color_fetcher, Arc::from(ranges)),
19959        );
19960        self.scrollbar_marker_state.dirty = true;
19961        cx.notify();
19962    }
19963
19964    pub fn highlight_background_key<T: 'static>(
19965        &mut self,
19966        key: usize,
19967        ranges: &[Range<Anchor>],
19968        color_fetcher: fn(&Theme) -> Hsla,
19969        cx: &mut Context<Self>,
19970    ) {
19971        self.background_highlights.insert(
19972            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19973            (color_fetcher, Arc::from(ranges)),
19974        );
19975        self.scrollbar_marker_state.dirty = true;
19976        cx.notify();
19977    }
19978
19979    pub fn clear_background_highlights<T: 'static>(
19980        &mut self,
19981        cx: &mut Context<Self>,
19982    ) -> Option<BackgroundHighlight> {
19983        let text_highlights = self
19984            .background_highlights
19985            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19986        if !text_highlights.1.is_empty() {
19987            self.scrollbar_marker_state.dirty = true;
19988            cx.notify();
19989        }
19990        Some(text_highlights)
19991    }
19992
19993    pub fn highlight_gutter<T: 'static>(
19994        &mut self,
19995        ranges: impl Into<Vec<Range<Anchor>>>,
19996        color_fetcher: fn(&App) -> Hsla,
19997        cx: &mut Context<Self>,
19998    ) {
19999        self.gutter_highlights
20000            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20001        cx.notify();
20002    }
20003
20004    pub fn clear_gutter_highlights<T: 'static>(
20005        &mut self,
20006        cx: &mut Context<Self>,
20007    ) -> Option<GutterHighlight> {
20008        cx.notify();
20009        self.gutter_highlights.remove(&TypeId::of::<T>())
20010    }
20011
20012    pub fn insert_gutter_highlight<T: 'static>(
20013        &mut self,
20014        range: Range<Anchor>,
20015        color_fetcher: fn(&App) -> Hsla,
20016        cx: &mut Context<Self>,
20017    ) {
20018        let snapshot = self.buffer().read(cx).snapshot(cx);
20019        let mut highlights = self
20020            .gutter_highlights
20021            .remove(&TypeId::of::<T>())
20022            .map(|(_, highlights)| highlights)
20023            .unwrap_or_default();
20024        let ix = highlights.binary_search_by(|highlight| {
20025            Ordering::Equal
20026                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20027                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20028        });
20029        if let Err(ix) = ix {
20030            highlights.insert(ix, range);
20031        }
20032        self.gutter_highlights
20033            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20034    }
20035
20036    pub fn remove_gutter_highlights<T: 'static>(
20037        &mut self,
20038        ranges_to_remove: Vec<Range<Anchor>>,
20039        cx: &mut Context<Self>,
20040    ) {
20041        let snapshot = self.buffer().read(cx).snapshot(cx);
20042        let Some((color_fetcher, mut gutter_highlights)) =
20043            self.gutter_highlights.remove(&TypeId::of::<T>())
20044        else {
20045            return;
20046        };
20047        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20048        gutter_highlights.retain(|highlight| {
20049            while let Some(range_to_remove) = ranges_to_remove.peek() {
20050                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20051                    Ordering::Less | Ordering::Equal => {
20052                        ranges_to_remove.next();
20053                    }
20054                    Ordering::Greater => {
20055                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20056                            Ordering::Less | Ordering::Equal => {
20057                                return false;
20058                            }
20059                            Ordering::Greater => break,
20060                        }
20061                    }
20062                }
20063            }
20064
20065            true
20066        });
20067        self.gutter_highlights
20068            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20069    }
20070
20071    #[cfg(feature = "test-support")]
20072    pub fn all_text_highlights(
20073        &self,
20074        window: &mut Window,
20075        cx: &mut Context<Self>,
20076    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20077        let snapshot = self.snapshot(window, cx);
20078        self.display_map.update(cx, |display_map, _| {
20079            display_map
20080                .all_text_highlights()
20081                .map(|highlight| {
20082                    let (style, ranges) = highlight.as_ref();
20083                    (
20084                        *style,
20085                        ranges
20086                            .iter()
20087                            .map(|range| range.clone().to_display_points(&snapshot))
20088                            .collect(),
20089                    )
20090                })
20091                .collect()
20092        })
20093    }
20094
20095    #[cfg(feature = "test-support")]
20096    pub fn all_text_background_highlights(
20097        &self,
20098        window: &mut Window,
20099        cx: &mut Context<Self>,
20100    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20101        let snapshot = self.snapshot(window, cx);
20102        let buffer = &snapshot.buffer_snapshot;
20103        let start = buffer.anchor_before(0);
20104        let end = buffer.anchor_after(buffer.len());
20105        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20106    }
20107
20108    #[cfg(any(test, feature = "test-support"))]
20109    pub fn sorted_background_highlights_in_range(
20110        &self,
20111        search_range: Range<Anchor>,
20112        display_snapshot: &DisplaySnapshot,
20113        theme: &Theme,
20114    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20115        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20116        res.sort_by(|a, b| {
20117            a.0.start
20118                .cmp(&b.0.start)
20119                .then_with(|| a.0.end.cmp(&b.0.end))
20120                .then_with(|| a.1.cmp(&b.1))
20121        });
20122        res
20123    }
20124
20125    #[cfg(feature = "test-support")]
20126    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20127        let snapshot = self.buffer().read(cx).snapshot(cx);
20128
20129        let highlights = self
20130            .background_highlights
20131            .get(&HighlightKey::Type(TypeId::of::<
20132                items::BufferSearchHighlights,
20133            >()));
20134
20135        if let Some((_color, ranges)) = highlights {
20136            ranges
20137                .iter()
20138                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20139                .collect_vec()
20140        } else {
20141            vec![]
20142        }
20143    }
20144
20145    fn document_highlights_for_position<'a>(
20146        &'a self,
20147        position: Anchor,
20148        buffer: &'a MultiBufferSnapshot,
20149    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20150        let read_highlights = self
20151            .background_highlights
20152            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20153            .map(|h| &h.1);
20154        let write_highlights = self
20155            .background_highlights
20156            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20157            .map(|h| &h.1);
20158        let left_position = position.bias_left(buffer);
20159        let right_position = position.bias_right(buffer);
20160        read_highlights
20161            .into_iter()
20162            .chain(write_highlights)
20163            .flat_map(move |ranges| {
20164                let start_ix = match ranges.binary_search_by(|probe| {
20165                    let cmp = probe.end.cmp(&left_position, buffer);
20166                    if cmp.is_ge() {
20167                        Ordering::Greater
20168                    } else {
20169                        Ordering::Less
20170                    }
20171                }) {
20172                    Ok(i) | Err(i) => i,
20173                };
20174
20175                ranges[start_ix..]
20176                    .iter()
20177                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20178            })
20179    }
20180
20181    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20182        self.background_highlights
20183            .get(&HighlightKey::Type(TypeId::of::<T>()))
20184            .is_some_and(|(_, highlights)| !highlights.is_empty())
20185    }
20186
20187    /// Returns all background highlights for a given range.
20188    ///
20189    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20190    pub fn background_highlights_in_range(
20191        &self,
20192        search_range: Range<Anchor>,
20193        display_snapshot: &DisplaySnapshot,
20194        theme: &Theme,
20195    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20196        let mut results = Vec::new();
20197        for (color_fetcher, ranges) in self.background_highlights.values() {
20198            let color = color_fetcher(theme);
20199            let start_ix = match ranges.binary_search_by(|probe| {
20200                let cmp = probe
20201                    .end
20202                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20203                if cmp.is_gt() {
20204                    Ordering::Greater
20205                } else {
20206                    Ordering::Less
20207                }
20208            }) {
20209                Ok(i) | Err(i) => i,
20210            };
20211            for range in &ranges[start_ix..] {
20212                if range
20213                    .start
20214                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20215                    .is_ge()
20216                {
20217                    break;
20218                }
20219
20220                let start = range.start.to_display_point(display_snapshot);
20221                let end = range.end.to_display_point(display_snapshot);
20222                results.push((start..end, color))
20223            }
20224        }
20225        results
20226    }
20227
20228    pub fn gutter_highlights_in_range(
20229        &self,
20230        search_range: Range<Anchor>,
20231        display_snapshot: &DisplaySnapshot,
20232        cx: &App,
20233    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20234        let mut results = Vec::new();
20235        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20236            let color = color_fetcher(cx);
20237            let start_ix = match ranges.binary_search_by(|probe| {
20238                let cmp = probe
20239                    .end
20240                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20241                if cmp.is_gt() {
20242                    Ordering::Greater
20243                } else {
20244                    Ordering::Less
20245                }
20246            }) {
20247                Ok(i) | Err(i) => i,
20248            };
20249            for range in &ranges[start_ix..] {
20250                if range
20251                    .start
20252                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20253                    .is_ge()
20254                {
20255                    break;
20256                }
20257
20258                let start = range.start.to_display_point(display_snapshot);
20259                let end = range.end.to_display_point(display_snapshot);
20260                results.push((start..end, color))
20261            }
20262        }
20263        results
20264    }
20265
20266    /// Get the text ranges corresponding to the redaction query
20267    pub fn redacted_ranges(
20268        &self,
20269        search_range: Range<Anchor>,
20270        display_snapshot: &DisplaySnapshot,
20271        cx: &App,
20272    ) -> Vec<Range<DisplayPoint>> {
20273        display_snapshot
20274            .buffer_snapshot
20275            .redacted_ranges(search_range, |file| {
20276                if let Some(file) = file {
20277                    file.is_private()
20278                        && EditorSettings::get(
20279                            Some(SettingsLocation {
20280                                worktree_id: file.worktree_id(cx),
20281                                path: file.path().as_ref(),
20282                            }),
20283                            cx,
20284                        )
20285                        .redact_private_values
20286                } else {
20287                    false
20288                }
20289            })
20290            .map(|range| {
20291                range.start.to_display_point(display_snapshot)
20292                    ..range.end.to_display_point(display_snapshot)
20293            })
20294            .collect()
20295    }
20296
20297    pub fn highlight_text_key<T: 'static>(
20298        &mut self,
20299        key: usize,
20300        ranges: Vec<Range<Anchor>>,
20301        style: HighlightStyle,
20302        cx: &mut Context<Self>,
20303    ) {
20304        self.display_map.update(cx, |map, _| {
20305            map.highlight_text(
20306                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20307                ranges,
20308                style,
20309            );
20310        });
20311        cx.notify();
20312    }
20313
20314    pub fn highlight_text<T: 'static>(
20315        &mut self,
20316        ranges: Vec<Range<Anchor>>,
20317        style: HighlightStyle,
20318        cx: &mut Context<Self>,
20319    ) {
20320        self.display_map.update(cx, |map, _| {
20321            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20322        });
20323        cx.notify();
20324    }
20325
20326    pub(crate) fn highlight_inlays<T: 'static>(
20327        &mut self,
20328        highlights: Vec<InlayHighlight>,
20329        style: HighlightStyle,
20330        cx: &mut Context<Self>,
20331    ) {
20332        self.display_map.update(cx, |map, _| {
20333            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20334        });
20335        cx.notify();
20336    }
20337
20338    pub fn text_highlights<'a, T: 'static>(
20339        &'a self,
20340        cx: &'a App,
20341    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20342        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20343    }
20344
20345    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20346        let cleared = self
20347            .display_map
20348            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20349        if cleared {
20350            cx.notify();
20351        }
20352    }
20353
20354    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20355        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20356            && self.focus_handle.is_focused(window)
20357    }
20358
20359    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20360        self.show_cursor_when_unfocused = is_enabled;
20361        cx.notify();
20362    }
20363
20364    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20365        cx.notify();
20366    }
20367
20368    fn on_debug_session_event(
20369        &mut self,
20370        _session: Entity<Session>,
20371        event: &SessionEvent,
20372        cx: &mut Context<Self>,
20373    ) {
20374        if let SessionEvent::InvalidateInlineValue = event {
20375            self.refresh_inline_values(cx);
20376        }
20377    }
20378
20379    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20380        let Some(project) = self.project.clone() else {
20381            return;
20382        };
20383
20384        if !self.inline_value_cache.enabled {
20385            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20386            self.splice_inlays(&inlays, Vec::new(), cx);
20387            return;
20388        }
20389
20390        let current_execution_position = self
20391            .highlighted_rows
20392            .get(&TypeId::of::<ActiveDebugLine>())
20393            .and_then(|lines| lines.last().map(|line| line.range.end));
20394
20395        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20396            let inline_values = editor
20397                .update(cx, |editor, cx| {
20398                    let Some(current_execution_position) = current_execution_position else {
20399                        return Some(Task::ready(Ok(Vec::new())));
20400                    };
20401
20402                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20403                        let snapshot = buffer.snapshot(cx);
20404
20405                        let excerpt = snapshot.excerpt_containing(
20406                            current_execution_position..current_execution_position,
20407                        )?;
20408
20409                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20410                    })?;
20411
20412                    let range =
20413                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20414
20415                    project.inline_values(buffer, range, cx)
20416                })
20417                .ok()
20418                .flatten()?
20419                .await
20420                .context("refreshing debugger inlays")
20421                .log_err()?;
20422
20423            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20424
20425            for (buffer_id, inline_value) in inline_values
20426                .into_iter()
20427                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20428            {
20429                buffer_inline_values
20430                    .entry(buffer_id)
20431                    .or_default()
20432                    .push(inline_value);
20433            }
20434
20435            editor
20436                .update(cx, |editor, cx| {
20437                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20438                    let mut new_inlays = Vec::default();
20439
20440                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20441                        let buffer_id = buffer_snapshot.remote_id();
20442                        buffer_inline_values
20443                            .get(&buffer_id)
20444                            .into_iter()
20445                            .flatten()
20446                            .for_each(|hint| {
20447                                let inlay = Inlay::debugger(
20448                                    post_inc(&mut editor.next_inlay_id),
20449                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20450                                    hint.text(),
20451                                );
20452                                if !inlay.text.chars().contains(&'\n') {
20453                                    new_inlays.push(inlay);
20454                                }
20455                            });
20456                    }
20457
20458                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20459                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20460
20461                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20462                })
20463                .ok()?;
20464            Some(())
20465        });
20466    }
20467
20468    fn on_buffer_event(
20469        &mut self,
20470        multibuffer: &Entity<MultiBuffer>,
20471        event: &multi_buffer::Event,
20472        window: &mut Window,
20473        cx: &mut Context<Self>,
20474    ) {
20475        match event {
20476            multi_buffer::Event::Edited {
20477                singleton_buffer_edited,
20478                edited_buffer,
20479            } => {
20480                self.scrollbar_marker_state.dirty = true;
20481                self.active_indent_guides_state.dirty = true;
20482                self.refresh_active_diagnostics(cx);
20483                self.refresh_code_actions(window, cx);
20484                self.refresh_selected_text_highlights(true, window, cx);
20485                self.refresh_single_line_folds(window, cx);
20486                refresh_matching_bracket_highlights(self, window, cx);
20487                if self.has_active_edit_prediction() {
20488                    self.update_visible_edit_prediction(window, cx);
20489                }
20490                if let Some(project) = self.project.as_ref()
20491                    && let Some(edited_buffer) = edited_buffer
20492                {
20493                    project.update(cx, |project, cx| {
20494                        self.registered_buffers
20495                            .entry(edited_buffer.read(cx).remote_id())
20496                            .or_insert_with(|| {
20497                                project.register_buffer_with_language_servers(edited_buffer, cx)
20498                            });
20499                    });
20500                }
20501                cx.emit(EditorEvent::BufferEdited);
20502                cx.emit(SearchEvent::MatchesInvalidated);
20503
20504                if let Some(buffer) = edited_buffer {
20505                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20506                }
20507
20508                if *singleton_buffer_edited {
20509                    if let Some(buffer) = edited_buffer
20510                        && buffer.read(cx).file().is_none()
20511                    {
20512                        cx.emit(EditorEvent::TitleChanged);
20513                    }
20514                    if let Some(project) = &self.project {
20515                        #[allow(clippy::mutable_key_type)]
20516                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20517                            multibuffer
20518                                .all_buffers()
20519                                .into_iter()
20520                                .filter_map(|buffer| {
20521                                    buffer.update(cx, |buffer, cx| {
20522                                        let language = buffer.language()?;
20523                                        let should_discard = project.update(cx, |project, cx| {
20524                                            project.is_local()
20525                                                && !project.has_language_servers_for(buffer, cx)
20526                                        });
20527                                        should_discard.not().then_some(language.clone())
20528                                    })
20529                                })
20530                                .collect::<HashSet<_>>()
20531                        });
20532                        if !languages_affected.is_empty() {
20533                            self.refresh_inlay_hints(
20534                                InlayHintRefreshReason::BufferEdited(languages_affected),
20535                                cx,
20536                            );
20537                        }
20538                    }
20539                }
20540
20541                let Some(project) = &self.project else { return };
20542                let (telemetry, is_via_ssh) = {
20543                    let project = project.read(cx);
20544                    let telemetry = project.client().telemetry().clone();
20545                    let is_via_ssh = project.is_via_remote_server();
20546                    (telemetry, is_via_ssh)
20547                };
20548                refresh_linked_ranges(self, window, cx);
20549                telemetry.log_edit_event("editor", is_via_ssh);
20550            }
20551            multi_buffer::Event::ExcerptsAdded {
20552                buffer,
20553                predecessor,
20554                excerpts,
20555            } => {
20556                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20557                let buffer_id = buffer.read(cx).remote_id();
20558                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20559                    && let Some(project) = &self.project
20560                {
20561                    update_uncommitted_diff_for_buffer(
20562                        cx.entity(),
20563                        project,
20564                        [buffer.clone()],
20565                        self.buffer.clone(),
20566                        cx,
20567                    )
20568                    .detach();
20569                }
20570                if self.active_diagnostics != ActiveDiagnostic::All {
20571                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20572                }
20573                cx.emit(EditorEvent::ExcerptsAdded {
20574                    buffer: buffer.clone(),
20575                    predecessor: *predecessor,
20576                    excerpts: excerpts.clone(),
20577                });
20578                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20579            }
20580            multi_buffer::Event::ExcerptsRemoved {
20581                ids,
20582                removed_buffer_ids,
20583            } => {
20584                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20585                let buffer = self.buffer.read(cx);
20586                self.registered_buffers
20587                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20588                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20589                cx.emit(EditorEvent::ExcerptsRemoved {
20590                    ids: ids.clone(),
20591                    removed_buffer_ids: removed_buffer_ids.clone(),
20592                });
20593            }
20594            multi_buffer::Event::ExcerptsEdited {
20595                excerpt_ids,
20596                buffer_ids,
20597            } => {
20598                self.display_map.update(cx, |map, cx| {
20599                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20600                });
20601                cx.emit(EditorEvent::ExcerptsEdited {
20602                    ids: excerpt_ids.clone(),
20603                });
20604            }
20605            multi_buffer::Event::ExcerptsExpanded { ids } => {
20606                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20607                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20608            }
20609            multi_buffer::Event::Reparsed(buffer_id) => {
20610                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20611                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20612
20613                cx.emit(EditorEvent::Reparsed(*buffer_id));
20614            }
20615            multi_buffer::Event::DiffHunksToggled => {
20616                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20617            }
20618            multi_buffer::Event::LanguageChanged(buffer_id) => {
20619                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20620                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20621                cx.emit(EditorEvent::Reparsed(*buffer_id));
20622                cx.notify();
20623            }
20624            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20625            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20626            multi_buffer::Event::FileHandleChanged
20627            | multi_buffer::Event::Reloaded
20628            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20629            multi_buffer::Event::DiagnosticsUpdated => {
20630                self.update_diagnostics_state(window, cx);
20631            }
20632            _ => {}
20633        };
20634    }
20635
20636    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20637        if !self.diagnostics_enabled() {
20638            return;
20639        }
20640        self.refresh_active_diagnostics(cx);
20641        self.refresh_inline_diagnostics(true, window, cx);
20642        self.scrollbar_marker_state.dirty = true;
20643        cx.notify();
20644    }
20645
20646    pub fn start_temporary_diff_override(&mut self) {
20647        self.load_diff_task.take();
20648        self.temporary_diff_override = true;
20649    }
20650
20651    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20652        self.temporary_diff_override = false;
20653        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20654        self.buffer.update(cx, |buffer, cx| {
20655            buffer.set_all_diff_hunks_collapsed(cx);
20656        });
20657
20658        if let Some(project) = self.project.clone() {
20659            self.load_diff_task = Some(
20660                update_uncommitted_diff_for_buffer(
20661                    cx.entity(),
20662                    &project,
20663                    self.buffer.read(cx).all_buffers(),
20664                    self.buffer.clone(),
20665                    cx,
20666                )
20667                .shared(),
20668            );
20669        }
20670    }
20671
20672    fn on_display_map_changed(
20673        &mut self,
20674        _: Entity<DisplayMap>,
20675        _: &mut Window,
20676        cx: &mut Context<Self>,
20677    ) {
20678        cx.notify();
20679    }
20680
20681    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20682        if self.diagnostics_enabled() {
20683            let new_severity = EditorSettings::get_global(cx)
20684                .diagnostics_max_severity
20685                .unwrap_or(DiagnosticSeverity::Hint);
20686            self.set_max_diagnostics_severity(new_severity, cx);
20687        }
20688        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20689        self.update_edit_prediction_settings(cx);
20690        self.refresh_edit_prediction(true, false, window, cx);
20691        self.refresh_inline_values(cx);
20692        self.refresh_inlay_hints(
20693            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20694                self.selections.newest_anchor().head(),
20695                &self.buffer.read(cx).snapshot(cx),
20696                cx,
20697            )),
20698            cx,
20699        );
20700
20701        let old_cursor_shape = self.cursor_shape;
20702        let old_show_breadcrumbs = self.show_breadcrumbs;
20703
20704        {
20705            let editor_settings = EditorSettings::get_global(cx);
20706            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20707            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20708            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20709            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20710        }
20711
20712        if old_cursor_shape != self.cursor_shape {
20713            cx.emit(EditorEvent::CursorShapeChanged);
20714        }
20715
20716        if old_show_breadcrumbs != self.show_breadcrumbs {
20717            cx.emit(EditorEvent::BreadcrumbsChanged);
20718        }
20719
20720        let project_settings = ProjectSettings::get_global(cx);
20721        self.serialize_dirty_buffers =
20722            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20723
20724        if self.mode.is_full() {
20725            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20726            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20727            if self.show_inline_diagnostics != show_inline_diagnostics {
20728                self.show_inline_diagnostics = show_inline_diagnostics;
20729                self.refresh_inline_diagnostics(false, window, cx);
20730            }
20731
20732            if self.git_blame_inline_enabled != inline_blame_enabled {
20733                self.toggle_git_blame_inline_internal(false, window, cx);
20734            }
20735
20736            let minimap_settings = EditorSettings::get_global(cx).minimap;
20737            if self.minimap_visibility != MinimapVisibility::Disabled {
20738                if self.minimap_visibility.settings_visibility()
20739                    != minimap_settings.minimap_enabled()
20740                {
20741                    self.set_minimap_visibility(
20742                        MinimapVisibility::for_mode(self.mode(), cx),
20743                        window,
20744                        cx,
20745                    );
20746                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20747                    minimap_entity.update(cx, |minimap_editor, cx| {
20748                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20749                    })
20750                }
20751            }
20752        }
20753
20754        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20755            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20756        }) {
20757            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20758                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20759            }
20760            self.refresh_colors(false, None, window, cx);
20761        }
20762
20763        cx.notify();
20764    }
20765
20766    pub fn set_searchable(&mut self, searchable: bool) {
20767        self.searchable = searchable;
20768    }
20769
20770    pub fn searchable(&self) -> bool {
20771        self.searchable
20772    }
20773
20774    fn open_proposed_changes_editor(
20775        &mut self,
20776        _: &OpenProposedChangesEditor,
20777        window: &mut Window,
20778        cx: &mut Context<Self>,
20779    ) {
20780        let Some(workspace) = self.workspace() else {
20781            cx.propagate();
20782            return;
20783        };
20784
20785        let selections = self.selections.all::<usize>(cx);
20786        let multi_buffer = self.buffer.read(cx);
20787        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20788        let mut new_selections_by_buffer = HashMap::default();
20789        for selection in selections {
20790            for (buffer, range, _) in
20791                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20792            {
20793                let mut range = range.to_point(buffer);
20794                range.start.column = 0;
20795                range.end.column = buffer.line_len(range.end.row);
20796                new_selections_by_buffer
20797                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20798                    .or_insert(Vec::new())
20799                    .push(range)
20800            }
20801        }
20802
20803        let proposed_changes_buffers = new_selections_by_buffer
20804            .into_iter()
20805            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20806            .collect::<Vec<_>>();
20807        let proposed_changes_editor = cx.new(|cx| {
20808            ProposedChangesEditor::new(
20809                "Proposed changes",
20810                proposed_changes_buffers,
20811                self.project.clone(),
20812                window,
20813                cx,
20814            )
20815        });
20816
20817        window.defer(cx, move |window, cx| {
20818            workspace.update(cx, |workspace, cx| {
20819                workspace.active_pane().update(cx, |pane, cx| {
20820                    pane.add_item(
20821                        Box::new(proposed_changes_editor),
20822                        true,
20823                        true,
20824                        None,
20825                        window,
20826                        cx,
20827                    );
20828                });
20829            });
20830        });
20831    }
20832
20833    pub fn open_excerpts_in_split(
20834        &mut self,
20835        _: &OpenExcerptsSplit,
20836        window: &mut Window,
20837        cx: &mut Context<Self>,
20838    ) {
20839        self.open_excerpts_common(None, true, window, cx)
20840    }
20841
20842    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20843        self.open_excerpts_common(None, false, window, cx)
20844    }
20845
20846    fn open_excerpts_common(
20847        &mut self,
20848        jump_data: Option<JumpData>,
20849        split: bool,
20850        window: &mut Window,
20851        cx: &mut Context<Self>,
20852    ) {
20853        let Some(workspace) = self.workspace() else {
20854            cx.propagate();
20855            return;
20856        };
20857
20858        if self.buffer.read(cx).is_singleton() {
20859            cx.propagate();
20860            return;
20861        }
20862
20863        let mut new_selections_by_buffer = HashMap::default();
20864        match &jump_data {
20865            Some(JumpData::MultiBufferPoint {
20866                excerpt_id,
20867                position,
20868                anchor,
20869                line_offset_from_top,
20870            }) => {
20871                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20872                if let Some(buffer) = multi_buffer_snapshot
20873                    .buffer_id_for_excerpt(*excerpt_id)
20874                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20875                {
20876                    let buffer_snapshot = buffer.read(cx).snapshot();
20877                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20878                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20879                    } else {
20880                        buffer_snapshot.clip_point(*position, Bias::Left)
20881                    };
20882                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20883                    new_selections_by_buffer.insert(
20884                        buffer,
20885                        (
20886                            vec![jump_to_offset..jump_to_offset],
20887                            Some(*line_offset_from_top),
20888                        ),
20889                    );
20890                }
20891            }
20892            Some(JumpData::MultiBufferRow {
20893                row,
20894                line_offset_from_top,
20895            }) => {
20896                let point = MultiBufferPoint::new(row.0, 0);
20897                if let Some((buffer, buffer_point, _)) =
20898                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20899                {
20900                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20901                    new_selections_by_buffer
20902                        .entry(buffer)
20903                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20904                        .0
20905                        .push(buffer_offset..buffer_offset)
20906                }
20907            }
20908            None => {
20909                let selections = self.selections.all::<usize>(cx);
20910                let multi_buffer = self.buffer.read(cx);
20911                for selection in selections {
20912                    for (snapshot, range, _, anchor) in multi_buffer
20913                        .snapshot(cx)
20914                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20915                    {
20916                        if let Some(anchor) = anchor {
20917                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20918                            else {
20919                                continue;
20920                            };
20921                            let offset = text::ToOffset::to_offset(
20922                                &anchor.text_anchor,
20923                                &buffer_handle.read(cx).snapshot(),
20924                            );
20925                            let range = offset..offset;
20926                            new_selections_by_buffer
20927                                .entry(buffer_handle)
20928                                .or_insert((Vec::new(), None))
20929                                .0
20930                                .push(range)
20931                        } else {
20932                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20933                            else {
20934                                continue;
20935                            };
20936                            new_selections_by_buffer
20937                                .entry(buffer_handle)
20938                                .or_insert((Vec::new(), None))
20939                                .0
20940                                .push(range)
20941                        }
20942                    }
20943                }
20944            }
20945        }
20946
20947        new_selections_by_buffer
20948            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20949
20950        if new_selections_by_buffer.is_empty() {
20951            return;
20952        }
20953
20954        // We defer the pane interaction because we ourselves are a workspace item
20955        // and activating a new item causes the pane to call a method on us reentrantly,
20956        // which panics if we're on the stack.
20957        window.defer(cx, move |window, cx| {
20958            workspace.update(cx, |workspace, cx| {
20959                let pane = if split {
20960                    workspace.adjacent_pane(window, cx)
20961                } else {
20962                    workspace.active_pane().clone()
20963                };
20964
20965                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20966                    let editor = buffer
20967                        .read(cx)
20968                        .file()
20969                        .is_none()
20970                        .then(|| {
20971                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20972                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20973                            // Instead, we try to activate the existing editor in the pane first.
20974                            let (editor, pane_item_index) =
20975                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20976                                    let editor = item.downcast::<Editor>()?;
20977                                    let singleton_buffer =
20978                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20979                                    if singleton_buffer == buffer {
20980                                        Some((editor, i))
20981                                    } else {
20982                                        None
20983                                    }
20984                                })?;
20985                            pane.update(cx, |pane, cx| {
20986                                pane.activate_item(pane_item_index, true, true, window, cx)
20987                            });
20988                            Some(editor)
20989                        })
20990                        .flatten()
20991                        .unwrap_or_else(|| {
20992                            workspace.open_project_item::<Self>(
20993                                pane.clone(),
20994                                buffer,
20995                                true,
20996                                true,
20997                                window,
20998                                cx,
20999                            )
21000                        });
21001
21002                    editor.update(cx, |editor, cx| {
21003                        let autoscroll = match scroll_offset {
21004                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21005                            None => Autoscroll::newest(),
21006                        };
21007                        let nav_history = editor.nav_history.take();
21008                        editor.change_selections(
21009                            SelectionEffects::scroll(autoscroll),
21010                            window,
21011                            cx,
21012                            |s| {
21013                                s.select_ranges(ranges);
21014                            },
21015                        );
21016                        editor.nav_history = nav_history;
21017                    });
21018                }
21019            })
21020        });
21021    }
21022
21023    // For now, don't allow opening excerpts in buffers that aren't backed by
21024    // regular project files.
21025    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21026        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21027    }
21028
21029    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21030        let snapshot = self.buffer.read(cx).read(cx);
21031        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21032        Some(
21033            ranges
21034                .iter()
21035                .map(move |range| {
21036                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21037                })
21038                .collect(),
21039        )
21040    }
21041
21042    fn selection_replacement_ranges(
21043        &self,
21044        range: Range<OffsetUtf16>,
21045        cx: &mut App,
21046    ) -> Vec<Range<OffsetUtf16>> {
21047        let selections = self.selections.all::<OffsetUtf16>(cx);
21048        let newest_selection = selections
21049            .iter()
21050            .max_by_key(|selection| selection.id)
21051            .unwrap();
21052        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21053        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21054        let snapshot = self.buffer.read(cx).read(cx);
21055        selections
21056            .into_iter()
21057            .map(|mut selection| {
21058                selection.start.0 =
21059                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21060                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21061                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21062                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21063            })
21064            .collect()
21065    }
21066
21067    fn report_editor_event(
21068        &self,
21069        reported_event: ReportEditorEvent,
21070        file_extension: Option<String>,
21071        cx: &App,
21072    ) {
21073        if cfg!(any(test, feature = "test-support")) {
21074            return;
21075        }
21076
21077        let Some(project) = &self.project else { return };
21078
21079        // If None, we are in a file without an extension
21080        let file = self
21081            .buffer
21082            .read(cx)
21083            .as_singleton()
21084            .and_then(|b| b.read(cx).file());
21085        let file_extension = file_extension.or(file
21086            .as_ref()
21087            .and_then(|file| Path::new(file.file_name(cx)).extension())
21088            .and_then(|e| e.to_str())
21089            .map(|a| a.to_string()));
21090
21091        let vim_mode = vim_enabled(cx);
21092
21093        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21094        let copilot_enabled = edit_predictions_provider
21095            == language::language_settings::EditPredictionProvider::Copilot;
21096        let copilot_enabled_for_language = self
21097            .buffer
21098            .read(cx)
21099            .language_settings(cx)
21100            .show_edit_predictions;
21101
21102        let project = project.read(cx);
21103        let event_type = reported_event.event_type();
21104
21105        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21106            telemetry::event!(
21107                event_type,
21108                type = if auto_saved {"autosave"} else {"manual"},
21109                file_extension,
21110                vim_mode,
21111                copilot_enabled,
21112                copilot_enabled_for_language,
21113                edit_predictions_provider,
21114                is_via_ssh = project.is_via_remote_server(),
21115            );
21116        } else {
21117            telemetry::event!(
21118                event_type,
21119                file_extension,
21120                vim_mode,
21121                copilot_enabled,
21122                copilot_enabled_for_language,
21123                edit_predictions_provider,
21124                is_via_ssh = project.is_via_remote_server(),
21125            );
21126        };
21127    }
21128
21129    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21130    /// with each line being an array of {text, highlight} objects.
21131    fn copy_highlight_json(
21132        &mut self,
21133        _: &CopyHighlightJson,
21134        window: &mut Window,
21135        cx: &mut Context<Self>,
21136    ) {
21137        #[derive(Serialize)]
21138        struct Chunk<'a> {
21139            text: String,
21140            highlight: Option<&'a str>,
21141        }
21142
21143        let snapshot = self.buffer.read(cx).snapshot(cx);
21144        let range = self
21145            .selected_text_range(false, window, cx)
21146            .and_then(|selection| {
21147                if selection.range.is_empty() {
21148                    None
21149                } else {
21150                    Some(selection.range)
21151                }
21152            })
21153            .unwrap_or_else(|| 0..snapshot.len());
21154
21155        let chunks = snapshot.chunks(range, true);
21156        let mut lines = Vec::new();
21157        let mut line: VecDeque<Chunk> = VecDeque::new();
21158
21159        let Some(style) = self.style.as_ref() else {
21160            return;
21161        };
21162
21163        for chunk in chunks {
21164            let highlight = chunk
21165                .syntax_highlight_id
21166                .and_then(|id| id.name(&style.syntax));
21167            let mut chunk_lines = chunk.text.split('\n').peekable();
21168            while let Some(text) = chunk_lines.next() {
21169                let mut merged_with_last_token = false;
21170                if let Some(last_token) = line.back_mut()
21171                    && last_token.highlight == highlight
21172                {
21173                    last_token.text.push_str(text);
21174                    merged_with_last_token = true;
21175                }
21176
21177                if !merged_with_last_token {
21178                    line.push_back(Chunk {
21179                        text: text.into(),
21180                        highlight,
21181                    });
21182                }
21183
21184                if chunk_lines.peek().is_some() {
21185                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21186                        line.pop_front();
21187                    }
21188                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21189                        line.pop_back();
21190                    }
21191
21192                    lines.push(mem::take(&mut line));
21193                }
21194            }
21195        }
21196
21197        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21198            return;
21199        };
21200        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21201    }
21202
21203    pub fn open_context_menu(
21204        &mut self,
21205        _: &OpenContextMenu,
21206        window: &mut Window,
21207        cx: &mut Context<Self>,
21208    ) {
21209        self.request_autoscroll(Autoscroll::newest(), cx);
21210        let position = self.selections.newest_display(cx).start;
21211        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21212    }
21213
21214    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21215        &self.inlay_hint_cache
21216    }
21217
21218    pub fn replay_insert_event(
21219        &mut self,
21220        text: &str,
21221        relative_utf16_range: Option<Range<isize>>,
21222        window: &mut Window,
21223        cx: &mut Context<Self>,
21224    ) {
21225        if !self.input_enabled {
21226            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21227            return;
21228        }
21229        if let Some(relative_utf16_range) = relative_utf16_range {
21230            let selections = self.selections.all::<OffsetUtf16>(cx);
21231            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21232                let new_ranges = selections.into_iter().map(|range| {
21233                    let start = OffsetUtf16(
21234                        range
21235                            .head()
21236                            .0
21237                            .saturating_add_signed(relative_utf16_range.start),
21238                    );
21239                    let end = OffsetUtf16(
21240                        range
21241                            .head()
21242                            .0
21243                            .saturating_add_signed(relative_utf16_range.end),
21244                    );
21245                    start..end
21246                });
21247                s.select_ranges(new_ranges);
21248            });
21249        }
21250
21251        self.handle_input(text, window, cx);
21252    }
21253
21254    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21255        let Some(provider) = self.semantics_provider.as_ref() else {
21256            return false;
21257        };
21258
21259        let mut supports = false;
21260        self.buffer().update(cx, |this, cx| {
21261            this.for_each_buffer(|buffer| {
21262                supports |= provider.supports_inlay_hints(buffer, cx);
21263            });
21264        });
21265
21266        supports
21267    }
21268
21269    pub fn is_focused(&self, window: &Window) -> bool {
21270        self.focus_handle.is_focused(window)
21271    }
21272
21273    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21274        cx.emit(EditorEvent::Focused);
21275
21276        if let Some(descendant) = self
21277            .last_focused_descendant
21278            .take()
21279            .and_then(|descendant| descendant.upgrade())
21280        {
21281            window.focus(&descendant);
21282        } else {
21283            if let Some(blame) = self.blame.as_ref() {
21284                blame.update(cx, GitBlame::focus)
21285            }
21286
21287            self.blink_manager.update(cx, BlinkManager::enable);
21288            self.show_cursor_names(window, cx);
21289            self.buffer.update(cx, |buffer, cx| {
21290                buffer.finalize_last_transaction(cx);
21291                if self.leader_id.is_none() {
21292                    buffer.set_active_selections(
21293                        &self.selections.disjoint_anchors_arc(),
21294                        self.selections.line_mode,
21295                        self.cursor_shape,
21296                        cx,
21297                    );
21298                }
21299            });
21300        }
21301    }
21302
21303    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21304        cx.emit(EditorEvent::FocusedIn)
21305    }
21306
21307    fn handle_focus_out(
21308        &mut self,
21309        event: FocusOutEvent,
21310        _window: &mut Window,
21311        cx: &mut Context<Self>,
21312    ) {
21313        if event.blurred != self.focus_handle {
21314            self.last_focused_descendant = Some(event.blurred);
21315        }
21316        self.selection_drag_state = SelectionDragState::None;
21317        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21318    }
21319
21320    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21321        self.blink_manager.update(cx, BlinkManager::disable);
21322        self.buffer
21323            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21324
21325        if let Some(blame) = self.blame.as_ref() {
21326            blame.update(cx, GitBlame::blur)
21327        }
21328        if !self.hover_state.focused(window, cx) {
21329            hide_hover(self, cx);
21330        }
21331        if !self
21332            .context_menu
21333            .borrow()
21334            .as_ref()
21335            .is_some_and(|context_menu| context_menu.focused(window, cx))
21336        {
21337            self.hide_context_menu(window, cx);
21338        }
21339        self.discard_edit_prediction(false, cx);
21340        cx.emit(EditorEvent::Blurred);
21341        cx.notify();
21342    }
21343
21344    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21345        let mut pending: String = window
21346            .pending_input_keystrokes()
21347            .into_iter()
21348            .flatten()
21349            .filter_map(|keystroke| {
21350                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21351                    keystroke.key_char.clone()
21352                } else {
21353                    None
21354                }
21355            })
21356            .collect();
21357
21358        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21359            pending = "".to_string();
21360        }
21361
21362        let existing_pending = self
21363            .text_highlights::<PendingInput>(cx)
21364            .map(|(_, ranges)| ranges.to_vec());
21365        if existing_pending.is_none() && pending.is_empty() {
21366            return;
21367        }
21368        let transaction =
21369            self.transact(window, cx, |this, window, cx| {
21370                let selections = this.selections.all::<usize>(cx);
21371                let edits = selections
21372                    .iter()
21373                    .map(|selection| (selection.end..selection.end, pending.clone()));
21374                this.edit(edits, cx);
21375                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21376                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21377                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21378                    }));
21379                });
21380                if let Some(existing_ranges) = existing_pending {
21381                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21382                    this.edit(edits, cx);
21383                }
21384            });
21385
21386        let snapshot = self.snapshot(window, cx);
21387        let ranges = self
21388            .selections
21389            .all::<usize>(cx)
21390            .into_iter()
21391            .map(|selection| {
21392                snapshot.buffer_snapshot.anchor_after(selection.end)
21393                    ..snapshot
21394                        .buffer_snapshot
21395                        .anchor_before(selection.end + pending.len())
21396            })
21397            .collect();
21398
21399        if pending.is_empty() {
21400            self.clear_highlights::<PendingInput>(cx);
21401        } else {
21402            self.highlight_text::<PendingInput>(
21403                ranges,
21404                HighlightStyle {
21405                    underline: Some(UnderlineStyle {
21406                        thickness: px(1.),
21407                        color: None,
21408                        wavy: false,
21409                    }),
21410                    ..Default::default()
21411                },
21412                cx,
21413            );
21414        }
21415
21416        self.ime_transaction = self.ime_transaction.or(transaction);
21417        if let Some(transaction) = self.ime_transaction {
21418            self.buffer.update(cx, |buffer, cx| {
21419                buffer.group_until_transaction(transaction, cx);
21420            });
21421        }
21422
21423        if self.text_highlights::<PendingInput>(cx).is_none() {
21424            self.ime_transaction.take();
21425        }
21426    }
21427
21428    pub fn register_action_renderer(
21429        &mut self,
21430        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21431    ) -> Subscription {
21432        let id = self.next_editor_action_id.post_inc();
21433        self.editor_actions
21434            .borrow_mut()
21435            .insert(id, Box::new(listener));
21436
21437        let editor_actions = self.editor_actions.clone();
21438        Subscription::new(move || {
21439            editor_actions.borrow_mut().remove(&id);
21440        })
21441    }
21442
21443    pub fn register_action<A: Action>(
21444        &mut self,
21445        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21446    ) -> Subscription {
21447        let id = self.next_editor_action_id.post_inc();
21448        let listener = Arc::new(listener);
21449        self.editor_actions.borrow_mut().insert(
21450            id,
21451            Box::new(move |_, window, _| {
21452                let listener = listener.clone();
21453                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21454                    let action = action.downcast_ref().unwrap();
21455                    if phase == DispatchPhase::Bubble {
21456                        listener(action, window, cx)
21457                    }
21458                })
21459            }),
21460        );
21461
21462        let editor_actions = self.editor_actions.clone();
21463        Subscription::new(move || {
21464            editor_actions.borrow_mut().remove(&id);
21465        })
21466    }
21467
21468    pub fn file_header_size(&self) -> u32 {
21469        FILE_HEADER_HEIGHT
21470    }
21471
21472    pub fn restore(
21473        &mut self,
21474        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21475        window: &mut Window,
21476        cx: &mut Context<Self>,
21477    ) {
21478        let workspace = self.workspace();
21479        let project = self.project();
21480        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21481            let mut tasks = Vec::new();
21482            for (buffer_id, changes) in revert_changes {
21483                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21484                    buffer.update(cx, |buffer, cx| {
21485                        buffer.edit(
21486                            changes
21487                                .into_iter()
21488                                .map(|(range, text)| (range, text.to_string())),
21489                            None,
21490                            cx,
21491                        );
21492                    });
21493
21494                    if let Some(project) =
21495                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21496                    {
21497                        project.update(cx, |project, cx| {
21498                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21499                        })
21500                    }
21501                }
21502            }
21503            tasks
21504        });
21505        cx.spawn_in(window, async move |_, cx| {
21506            for (buffer, task) in save_tasks {
21507                let result = task.await;
21508                if result.is_err() {
21509                    let Some(path) = buffer
21510                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21511                        .ok()
21512                    else {
21513                        continue;
21514                    };
21515                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21516                        let Some(task) = cx
21517                            .update_window_entity(workspace, |workspace, window, cx| {
21518                                workspace
21519                                    .open_path_preview(path, None, false, false, false, window, cx)
21520                            })
21521                            .ok()
21522                        else {
21523                            continue;
21524                        };
21525                        task.await.log_err();
21526                    }
21527                }
21528            }
21529        })
21530        .detach();
21531        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21532            selections.refresh()
21533        });
21534    }
21535
21536    pub fn to_pixel_point(
21537        &self,
21538        source: multi_buffer::Anchor,
21539        editor_snapshot: &EditorSnapshot,
21540        window: &mut Window,
21541    ) -> Option<gpui::Point<Pixels>> {
21542        let source_point = source.to_display_point(editor_snapshot);
21543        self.display_to_pixel_point(source_point, editor_snapshot, window)
21544    }
21545
21546    pub fn display_to_pixel_point(
21547        &self,
21548        source: DisplayPoint,
21549        editor_snapshot: &EditorSnapshot,
21550        window: &mut Window,
21551    ) -> Option<gpui::Point<Pixels>> {
21552        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21553        let text_layout_details = self.text_layout_details(window);
21554        let scroll_top = text_layout_details
21555            .scroll_anchor
21556            .scroll_position(editor_snapshot)
21557            .y;
21558
21559        if source.row().as_f32() < scroll_top.floor() {
21560            return None;
21561        }
21562        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21563        let source_y = line_height * (source.row().as_f32() - scroll_top);
21564        Some(gpui::Point::new(source_x, source_y))
21565    }
21566
21567    pub fn has_visible_completions_menu(&self) -> bool {
21568        !self.edit_prediction_preview_is_active()
21569            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21570                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21571            })
21572    }
21573
21574    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21575        if self.mode.is_minimap() {
21576            return;
21577        }
21578        self.addons
21579            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21580    }
21581
21582    pub fn unregister_addon<T: Addon>(&mut self) {
21583        self.addons.remove(&std::any::TypeId::of::<T>());
21584    }
21585
21586    pub fn addon<T: Addon>(&self) -> Option<&T> {
21587        let type_id = std::any::TypeId::of::<T>();
21588        self.addons
21589            .get(&type_id)
21590            .and_then(|item| item.to_any().downcast_ref::<T>())
21591    }
21592
21593    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21594        let type_id = std::any::TypeId::of::<T>();
21595        self.addons
21596            .get_mut(&type_id)
21597            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21598    }
21599
21600    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21601        let text_layout_details = self.text_layout_details(window);
21602        let style = &text_layout_details.editor_style;
21603        let font_id = window.text_system().resolve_font(&style.text.font());
21604        let font_size = style.text.font_size.to_pixels(window.rem_size());
21605        let line_height = style.text.line_height_in_pixels(window.rem_size());
21606        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21607        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21608
21609        CharacterDimensions {
21610            em_width,
21611            em_advance,
21612            line_height,
21613        }
21614    }
21615
21616    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21617        self.load_diff_task.clone()
21618    }
21619
21620    fn read_metadata_from_db(
21621        &mut self,
21622        item_id: u64,
21623        workspace_id: WorkspaceId,
21624        window: &mut Window,
21625        cx: &mut Context<Editor>,
21626    ) {
21627        if self.is_singleton(cx)
21628            && !self.mode.is_minimap()
21629            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21630        {
21631            let buffer_snapshot = OnceCell::new();
21632
21633            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21634                && !folds.is_empty()
21635            {
21636                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21637                self.fold_ranges(
21638                    folds
21639                        .into_iter()
21640                        .map(|(start, end)| {
21641                            snapshot.clip_offset(start, Bias::Left)
21642                                ..snapshot.clip_offset(end, Bias::Right)
21643                        })
21644                        .collect(),
21645                    false,
21646                    window,
21647                    cx,
21648                );
21649            }
21650
21651            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21652                && !selections.is_empty()
21653            {
21654                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21655                // skip adding the initial selection to selection history
21656                self.selection_history.mode = SelectionHistoryMode::Skipping;
21657                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21658                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21659                        snapshot.clip_offset(start, Bias::Left)
21660                            ..snapshot.clip_offset(end, Bias::Right)
21661                    }));
21662                });
21663                self.selection_history.mode = SelectionHistoryMode::Normal;
21664            };
21665        }
21666
21667        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21668    }
21669
21670    fn update_lsp_data(
21671        &mut self,
21672        ignore_cache: bool,
21673        for_buffer: Option<BufferId>,
21674        window: &mut Window,
21675        cx: &mut Context<'_, Self>,
21676    ) {
21677        self.pull_diagnostics(for_buffer, window, cx);
21678        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21679    }
21680}
21681
21682fn vim_enabled(cx: &App) -> bool {
21683    vim_mode_setting::VimModeSetting::try_get(cx)
21684        .map(|vim_mode| vim_mode.0)
21685        .unwrap_or(false)
21686}
21687
21688fn process_completion_for_edit(
21689    completion: &Completion,
21690    intent: CompletionIntent,
21691    buffer: &Entity<Buffer>,
21692    cursor_position: &text::Anchor,
21693    cx: &mut Context<Editor>,
21694) -> CompletionEdit {
21695    let buffer = buffer.read(cx);
21696    let buffer_snapshot = buffer.snapshot();
21697    let (snippet, new_text) = if completion.is_snippet() {
21698        // Workaround for typescript language server issues so that methods don't expand within
21699        // strings and functions with type expressions. The previous point is used because the query
21700        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21701        let mut snippet_source = completion.new_text.clone();
21702        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21703        previous_point.column = previous_point.column.saturating_sub(1);
21704        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21705            && scope.prefers_label_for_snippet_in_completion()
21706            && let Some(label) = completion.label()
21707            && matches!(
21708                completion.kind(),
21709                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21710            )
21711        {
21712            snippet_source = label;
21713        }
21714        match Snippet::parse(&snippet_source).log_err() {
21715            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21716            None => (None, completion.new_text.clone()),
21717        }
21718    } else {
21719        (None, completion.new_text.clone())
21720    };
21721
21722    let mut range_to_replace = {
21723        let replace_range = &completion.replace_range;
21724        if let CompletionSource::Lsp {
21725            insert_range: Some(insert_range),
21726            ..
21727        } = &completion.source
21728        {
21729            debug_assert_eq!(
21730                insert_range.start, replace_range.start,
21731                "insert_range and replace_range should start at the same position"
21732            );
21733            debug_assert!(
21734                insert_range
21735                    .start
21736                    .cmp(cursor_position, &buffer_snapshot)
21737                    .is_le(),
21738                "insert_range should start before or at cursor position"
21739            );
21740            debug_assert!(
21741                replace_range
21742                    .start
21743                    .cmp(cursor_position, &buffer_snapshot)
21744                    .is_le(),
21745                "replace_range should start before or at cursor position"
21746            );
21747
21748            let should_replace = match intent {
21749                CompletionIntent::CompleteWithInsert => false,
21750                CompletionIntent::CompleteWithReplace => true,
21751                CompletionIntent::Complete | CompletionIntent::Compose => {
21752                    let insert_mode =
21753                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21754                            .completions
21755                            .lsp_insert_mode;
21756                    match insert_mode {
21757                        LspInsertMode::Insert => false,
21758                        LspInsertMode::Replace => true,
21759                        LspInsertMode::ReplaceSubsequence => {
21760                            let mut text_to_replace = buffer.chars_for_range(
21761                                buffer.anchor_before(replace_range.start)
21762                                    ..buffer.anchor_after(replace_range.end),
21763                            );
21764                            let mut current_needle = text_to_replace.next();
21765                            for haystack_ch in completion.label.text.chars() {
21766                                if let Some(needle_ch) = current_needle
21767                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21768                                {
21769                                    current_needle = text_to_replace.next();
21770                                }
21771                            }
21772                            current_needle.is_none()
21773                        }
21774                        LspInsertMode::ReplaceSuffix => {
21775                            if replace_range
21776                                .end
21777                                .cmp(cursor_position, &buffer_snapshot)
21778                                .is_gt()
21779                            {
21780                                let range_after_cursor = *cursor_position..replace_range.end;
21781                                let text_after_cursor = buffer
21782                                    .text_for_range(
21783                                        buffer.anchor_before(range_after_cursor.start)
21784                                            ..buffer.anchor_after(range_after_cursor.end),
21785                                    )
21786                                    .collect::<String>()
21787                                    .to_ascii_lowercase();
21788                                completion
21789                                    .label
21790                                    .text
21791                                    .to_ascii_lowercase()
21792                                    .ends_with(&text_after_cursor)
21793                            } else {
21794                                true
21795                            }
21796                        }
21797                    }
21798                }
21799            };
21800
21801            if should_replace {
21802                replace_range.clone()
21803            } else {
21804                insert_range.clone()
21805            }
21806        } else {
21807            replace_range.clone()
21808        }
21809    };
21810
21811    if range_to_replace
21812        .end
21813        .cmp(cursor_position, &buffer_snapshot)
21814        .is_lt()
21815    {
21816        range_to_replace.end = *cursor_position;
21817    }
21818
21819    CompletionEdit {
21820        new_text,
21821        replace_range: range_to_replace.to_offset(buffer),
21822        snippet,
21823    }
21824}
21825
21826struct CompletionEdit {
21827    new_text: String,
21828    replace_range: Range<usize>,
21829    snippet: Option<Snippet>,
21830}
21831
21832fn insert_extra_newline_brackets(
21833    buffer: &MultiBufferSnapshot,
21834    range: Range<usize>,
21835    language: &language::LanguageScope,
21836) -> bool {
21837    let leading_whitespace_len = buffer
21838        .reversed_chars_at(range.start)
21839        .take_while(|c| c.is_whitespace() && *c != '\n')
21840        .map(|c| c.len_utf8())
21841        .sum::<usize>();
21842    let trailing_whitespace_len = buffer
21843        .chars_at(range.end)
21844        .take_while(|c| c.is_whitespace() && *c != '\n')
21845        .map(|c| c.len_utf8())
21846        .sum::<usize>();
21847    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21848
21849    language.brackets().any(|(pair, enabled)| {
21850        let pair_start = pair.start.trim_end();
21851        let pair_end = pair.end.trim_start();
21852
21853        enabled
21854            && pair.newline
21855            && buffer.contains_str_at(range.end, pair_end)
21856            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21857    })
21858}
21859
21860fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21861    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21862        [(buffer, range, _)] => (*buffer, range.clone()),
21863        _ => return false,
21864    };
21865    let pair = {
21866        let mut result: Option<BracketMatch> = None;
21867
21868        for pair in buffer
21869            .all_bracket_ranges(range.clone())
21870            .filter(move |pair| {
21871                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21872            })
21873        {
21874            let len = pair.close_range.end - pair.open_range.start;
21875
21876            if let Some(existing) = &result {
21877                let existing_len = existing.close_range.end - existing.open_range.start;
21878                if len > existing_len {
21879                    continue;
21880                }
21881            }
21882
21883            result = Some(pair);
21884        }
21885
21886        result
21887    };
21888    let Some(pair) = pair else {
21889        return false;
21890    };
21891    pair.newline_only
21892        && buffer
21893            .chars_for_range(pair.open_range.end..range.start)
21894            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21895            .all(|c| c.is_whitespace() && c != '\n')
21896}
21897
21898fn update_uncommitted_diff_for_buffer(
21899    editor: Entity<Editor>,
21900    project: &Entity<Project>,
21901    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21902    buffer: Entity<MultiBuffer>,
21903    cx: &mut App,
21904) -> Task<()> {
21905    let mut tasks = Vec::new();
21906    project.update(cx, |project, cx| {
21907        for buffer in buffers {
21908            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21909                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21910            }
21911        }
21912    });
21913    cx.spawn(async move |cx| {
21914        let diffs = future::join_all(tasks).await;
21915        if editor
21916            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21917            .unwrap_or(false)
21918        {
21919            return;
21920        }
21921
21922        buffer
21923            .update(cx, |buffer, cx| {
21924                for diff in diffs.into_iter().flatten() {
21925                    buffer.add_diff(diff, cx);
21926                }
21927            })
21928            .ok();
21929    })
21930}
21931
21932fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21933    let tab_size = tab_size.get() as usize;
21934    let mut width = offset;
21935
21936    for ch in text.chars() {
21937        width += if ch == '\t' {
21938            tab_size - (width % tab_size)
21939        } else {
21940            1
21941        };
21942    }
21943
21944    width - offset
21945}
21946
21947#[cfg(test)]
21948mod tests {
21949    use super::*;
21950
21951    #[test]
21952    fn test_string_size_with_expanded_tabs() {
21953        let nz = |val| NonZeroU32::new(val).unwrap();
21954        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21955        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21956        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21957        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21958        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21959        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21960        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21961        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21962    }
21963}
21964
21965/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21966struct WordBreakingTokenizer<'a> {
21967    input: &'a str,
21968}
21969
21970impl<'a> WordBreakingTokenizer<'a> {
21971    fn new(input: &'a str) -> Self {
21972        Self { input }
21973    }
21974}
21975
21976fn is_char_ideographic(ch: char) -> bool {
21977    use unicode_script::Script::*;
21978    use unicode_script::UnicodeScript;
21979    matches!(ch.script(), Han | Tangut | Yi)
21980}
21981
21982fn is_grapheme_ideographic(text: &str) -> bool {
21983    text.chars().any(is_char_ideographic)
21984}
21985
21986fn is_grapheme_whitespace(text: &str) -> bool {
21987    text.chars().any(|x| x.is_whitespace())
21988}
21989
21990fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21991    text.chars()
21992        .next()
21993        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21994}
21995
21996#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21997enum WordBreakToken<'a> {
21998    Word { token: &'a str, grapheme_len: usize },
21999    InlineWhitespace { token: &'a str, grapheme_len: usize },
22000    Newline,
22001}
22002
22003impl<'a> Iterator for WordBreakingTokenizer<'a> {
22004    /// Yields a span, the count of graphemes in the token, and whether it was
22005    /// whitespace. Note that it also breaks at word boundaries.
22006    type Item = WordBreakToken<'a>;
22007
22008    fn next(&mut self) -> Option<Self::Item> {
22009        use unicode_segmentation::UnicodeSegmentation;
22010        if self.input.is_empty() {
22011            return None;
22012        }
22013
22014        let mut iter = self.input.graphemes(true).peekable();
22015        let mut offset = 0;
22016        let mut grapheme_len = 0;
22017        if let Some(first_grapheme) = iter.next() {
22018            let is_newline = first_grapheme == "\n";
22019            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22020            offset += first_grapheme.len();
22021            grapheme_len += 1;
22022            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22023                if let Some(grapheme) = iter.peek().copied()
22024                    && should_stay_with_preceding_ideograph(grapheme)
22025                {
22026                    offset += grapheme.len();
22027                    grapheme_len += 1;
22028                }
22029            } else {
22030                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22031                let mut next_word_bound = words.peek().copied();
22032                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22033                    next_word_bound = words.next();
22034                }
22035                while let Some(grapheme) = iter.peek().copied() {
22036                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22037                        break;
22038                    };
22039                    if is_grapheme_whitespace(grapheme) != is_whitespace
22040                        || (grapheme == "\n") != is_newline
22041                    {
22042                        break;
22043                    };
22044                    offset += grapheme.len();
22045                    grapheme_len += 1;
22046                    iter.next();
22047                }
22048            }
22049            let token = &self.input[..offset];
22050            self.input = &self.input[offset..];
22051            if token == "\n" {
22052                Some(WordBreakToken::Newline)
22053            } else if is_whitespace {
22054                Some(WordBreakToken::InlineWhitespace {
22055                    token,
22056                    grapheme_len,
22057                })
22058            } else {
22059                Some(WordBreakToken::Word {
22060                    token,
22061                    grapheme_len,
22062                })
22063            }
22064        } else {
22065            None
22066        }
22067    }
22068}
22069
22070#[test]
22071fn test_word_breaking_tokenizer() {
22072    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22073        ("", &[]),
22074        ("  ", &[whitespace("  ", 2)]),
22075        ("Ʒ", &[word("Ʒ", 1)]),
22076        ("Ǽ", &[word("Ǽ", 1)]),
22077        ("", &[word("", 1)]),
22078        ("⋑⋑", &[word("⋑⋑", 2)]),
22079        (
22080            "原理,进而",
22081            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22082        ),
22083        (
22084            "hello world",
22085            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22086        ),
22087        (
22088            "hello, world",
22089            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22090        ),
22091        (
22092            "  hello world",
22093            &[
22094                whitespace("  ", 2),
22095                word("hello", 5),
22096                whitespace(" ", 1),
22097                word("world", 5),
22098            ],
22099        ),
22100        (
22101            "这是什么 \n 钢笔",
22102            &[
22103                word("", 1),
22104                word("", 1),
22105                word("", 1),
22106                word("", 1),
22107                whitespace(" ", 1),
22108                newline(),
22109                whitespace(" ", 1),
22110                word("", 1),
22111                word("", 1),
22112            ],
22113        ),
22114        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22115    ];
22116
22117    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22118        WordBreakToken::Word {
22119            token,
22120            grapheme_len,
22121        }
22122    }
22123
22124    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22125        WordBreakToken::InlineWhitespace {
22126            token,
22127            grapheme_len,
22128        }
22129    }
22130
22131    fn newline() -> WordBreakToken<'static> {
22132        WordBreakToken::Newline
22133    }
22134
22135    for (input, result) in tests {
22136        assert_eq!(
22137            WordBreakingTokenizer::new(input)
22138                .collect::<Vec<_>>()
22139                .as_slice(),
22140            *result,
22141        );
22142    }
22143}
22144
22145fn wrap_with_prefix(
22146    first_line_prefix: String,
22147    subsequent_lines_prefix: String,
22148    unwrapped_text: String,
22149    wrap_column: usize,
22150    tab_size: NonZeroU32,
22151    preserve_existing_whitespace: bool,
22152) -> String {
22153    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22154    let subsequent_lines_prefix_len =
22155        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22156    let mut wrapped_text = String::new();
22157    let mut current_line = first_line_prefix;
22158    let mut is_first_line = true;
22159
22160    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22161    let mut current_line_len = first_line_prefix_len;
22162    let mut in_whitespace = false;
22163    for token in tokenizer {
22164        let have_preceding_whitespace = in_whitespace;
22165        match token {
22166            WordBreakToken::Word {
22167                token,
22168                grapheme_len,
22169            } => {
22170                in_whitespace = false;
22171                let current_prefix_len = if is_first_line {
22172                    first_line_prefix_len
22173                } else {
22174                    subsequent_lines_prefix_len
22175                };
22176                if current_line_len + grapheme_len > wrap_column
22177                    && current_line_len != current_prefix_len
22178                {
22179                    wrapped_text.push_str(current_line.trim_end());
22180                    wrapped_text.push('\n');
22181                    is_first_line = false;
22182                    current_line = subsequent_lines_prefix.clone();
22183                    current_line_len = subsequent_lines_prefix_len;
22184                }
22185                current_line.push_str(token);
22186                current_line_len += grapheme_len;
22187            }
22188            WordBreakToken::InlineWhitespace {
22189                mut token,
22190                mut grapheme_len,
22191            } => {
22192                in_whitespace = true;
22193                if have_preceding_whitespace && !preserve_existing_whitespace {
22194                    continue;
22195                }
22196                if !preserve_existing_whitespace {
22197                    token = " ";
22198                    grapheme_len = 1;
22199                }
22200                let current_prefix_len = if is_first_line {
22201                    first_line_prefix_len
22202                } else {
22203                    subsequent_lines_prefix_len
22204                };
22205                if current_line_len + grapheme_len > wrap_column {
22206                    wrapped_text.push_str(current_line.trim_end());
22207                    wrapped_text.push('\n');
22208                    is_first_line = false;
22209                    current_line = subsequent_lines_prefix.clone();
22210                    current_line_len = subsequent_lines_prefix_len;
22211                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22212                    current_line.push_str(token);
22213                    current_line_len += grapheme_len;
22214                }
22215            }
22216            WordBreakToken::Newline => {
22217                in_whitespace = true;
22218                let current_prefix_len = if is_first_line {
22219                    first_line_prefix_len
22220                } else {
22221                    subsequent_lines_prefix_len
22222                };
22223                if preserve_existing_whitespace {
22224                    wrapped_text.push_str(current_line.trim_end());
22225                    wrapped_text.push('\n');
22226                    is_first_line = false;
22227                    current_line = subsequent_lines_prefix.clone();
22228                    current_line_len = subsequent_lines_prefix_len;
22229                } else if have_preceding_whitespace {
22230                    continue;
22231                } else if current_line_len + 1 > wrap_column
22232                    && current_line_len != current_prefix_len
22233                {
22234                    wrapped_text.push_str(current_line.trim_end());
22235                    wrapped_text.push('\n');
22236                    is_first_line = false;
22237                    current_line = subsequent_lines_prefix.clone();
22238                    current_line_len = subsequent_lines_prefix_len;
22239                } else if current_line_len != current_prefix_len {
22240                    current_line.push(' ');
22241                    current_line_len += 1;
22242                }
22243            }
22244        }
22245    }
22246
22247    if !current_line.is_empty() {
22248        wrapped_text.push_str(&current_line);
22249    }
22250    wrapped_text
22251}
22252
22253#[test]
22254fn test_wrap_with_prefix() {
22255    assert_eq!(
22256        wrap_with_prefix(
22257            "# ".to_string(),
22258            "# ".to_string(),
22259            "abcdefg".to_string(),
22260            4,
22261            NonZeroU32::new(4).unwrap(),
22262            false,
22263        ),
22264        "# abcdefg"
22265    );
22266    assert_eq!(
22267        wrap_with_prefix(
22268            "".to_string(),
22269            "".to_string(),
22270            "\thello world".to_string(),
22271            8,
22272            NonZeroU32::new(4).unwrap(),
22273            false,
22274        ),
22275        "hello\nworld"
22276    );
22277    assert_eq!(
22278        wrap_with_prefix(
22279            "// ".to_string(),
22280            "// ".to_string(),
22281            "xx \nyy zz aa bb cc".to_string(),
22282            12,
22283            NonZeroU32::new(4).unwrap(),
22284            false,
22285        ),
22286        "// xx yy zz\n// aa bb cc"
22287    );
22288    assert_eq!(
22289        wrap_with_prefix(
22290            String::new(),
22291            String::new(),
22292            "这是什么 \n 钢笔".to_string(),
22293            3,
22294            NonZeroU32::new(4).unwrap(),
22295            false,
22296        ),
22297        "这是什\n么 钢\n"
22298    );
22299}
22300
22301pub trait CollaborationHub {
22302    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22303    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22304    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22305}
22306
22307impl CollaborationHub for Entity<Project> {
22308    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22309        self.read(cx).collaborators()
22310    }
22311
22312    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22313        self.read(cx).user_store().read(cx).participant_indices()
22314    }
22315
22316    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22317        let this = self.read(cx);
22318        let user_ids = this.collaborators().values().map(|c| c.user_id);
22319        this.user_store().read(cx).participant_names(user_ids, cx)
22320    }
22321}
22322
22323pub trait SemanticsProvider {
22324    fn hover(
22325        &self,
22326        buffer: &Entity<Buffer>,
22327        position: text::Anchor,
22328        cx: &mut App,
22329    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22330
22331    fn inline_values(
22332        &self,
22333        buffer_handle: Entity<Buffer>,
22334        range: Range<text::Anchor>,
22335        cx: &mut App,
22336    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22337
22338    fn inlay_hints(
22339        &self,
22340        buffer_handle: Entity<Buffer>,
22341        range: Range<text::Anchor>,
22342        cx: &mut App,
22343    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22344
22345    fn resolve_inlay_hint(
22346        &self,
22347        hint: InlayHint,
22348        buffer_handle: Entity<Buffer>,
22349        server_id: LanguageServerId,
22350        cx: &mut App,
22351    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22352
22353    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22354
22355    fn document_highlights(
22356        &self,
22357        buffer: &Entity<Buffer>,
22358        position: text::Anchor,
22359        cx: &mut App,
22360    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22361
22362    fn definitions(
22363        &self,
22364        buffer: &Entity<Buffer>,
22365        position: text::Anchor,
22366        kind: GotoDefinitionKind,
22367        cx: &mut App,
22368    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22369
22370    fn range_for_rename(
22371        &self,
22372        buffer: &Entity<Buffer>,
22373        position: text::Anchor,
22374        cx: &mut App,
22375    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22376
22377    fn perform_rename(
22378        &self,
22379        buffer: &Entity<Buffer>,
22380        position: text::Anchor,
22381        new_name: String,
22382        cx: &mut App,
22383    ) -> Option<Task<Result<ProjectTransaction>>>;
22384}
22385
22386pub trait CompletionProvider {
22387    fn completions(
22388        &self,
22389        excerpt_id: ExcerptId,
22390        buffer: &Entity<Buffer>,
22391        buffer_position: text::Anchor,
22392        trigger: CompletionContext,
22393        window: &mut Window,
22394        cx: &mut Context<Editor>,
22395    ) -> Task<Result<Vec<CompletionResponse>>>;
22396
22397    fn resolve_completions(
22398        &self,
22399        _buffer: Entity<Buffer>,
22400        _completion_indices: Vec<usize>,
22401        _completions: Rc<RefCell<Box<[Completion]>>>,
22402        _cx: &mut Context<Editor>,
22403    ) -> Task<Result<bool>> {
22404        Task::ready(Ok(false))
22405    }
22406
22407    fn apply_additional_edits_for_completion(
22408        &self,
22409        _buffer: Entity<Buffer>,
22410        _completions: Rc<RefCell<Box<[Completion]>>>,
22411        _completion_index: usize,
22412        _push_to_history: bool,
22413        _cx: &mut Context<Editor>,
22414    ) -> Task<Result<Option<language::Transaction>>> {
22415        Task::ready(Ok(None))
22416    }
22417
22418    fn is_completion_trigger(
22419        &self,
22420        buffer: &Entity<Buffer>,
22421        position: language::Anchor,
22422        text: &str,
22423        trigger_in_words: bool,
22424        menu_is_open: bool,
22425        cx: &mut Context<Editor>,
22426    ) -> bool;
22427
22428    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22429
22430    fn sort_completions(&self) -> bool {
22431        true
22432    }
22433
22434    fn filter_completions(&self) -> bool {
22435        true
22436    }
22437}
22438
22439pub trait CodeActionProvider {
22440    fn id(&self) -> Arc<str>;
22441
22442    fn code_actions(
22443        &self,
22444        buffer: &Entity<Buffer>,
22445        range: Range<text::Anchor>,
22446        window: &mut Window,
22447        cx: &mut App,
22448    ) -> Task<Result<Vec<CodeAction>>>;
22449
22450    fn apply_code_action(
22451        &self,
22452        buffer_handle: Entity<Buffer>,
22453        action: CodeAction,
22454        excerpt_id: ExcerptId,
22455        push_to_history: bool,
22456        window: &mut Window,
22457        cx: &mut App,
22458    ) -> Task<Result<ProjectTransaction>>;
22459}
22460
22461impl CodeActionProvider for Entity<Project> {
22462    fn id(&self) -> Arc<str> {
22463        "project".into()
22464    }
22465
22466    fn code_actions(
22467        &self,
22468        buffer: &Entity<Buffer>,
22469        range: Range<text::Anchor>,
22470        _window: &mut Window,
22471        cx: &mut App,
22472    ) -> Task<Result<Vec<CodeAction>>> {
22473        self.update(cx, |project, cx| {
22474            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22475            let code_actions = project.code_actions(buffer, range, None, cx);
22476            cx.background_spawn(async move {
22477                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22478                Ok(code_lens_actions
22479                    .context("code lens fetch")?
22480                    .into_iter()
22481                    .flatten()
22482                    .chain(
22483                        code_actions
22484                            .context("code action fetch")?
22485                            .into_iter()
22486                            .flatten(),
22487                    )
22488                    .collect())
22489            })
22490        })
22491    }
22492
22493    fn apply_code_action(
22494        &self,
22495        buffer_handle: Entity<Buffer>,
22496        action: CodeAction,
22497        _excerpt_id: ExcerptId,
22498        push_to_history: bool,
22499        _window: &mut Window,
22500        cx: &mut App,
22501    ) -> Task<Result<ProjectTransaction>> {
22502        self.update(cx, |project, cx| {
22503            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22504        })
22505    }
22506}
22507
22508fn snippet_completions(
22509    project: &Project,
22510    buffer: &Entity<Buffer>,
22511    buffer_position: text::Anchor,
22512    cx: &mut App,
22513) -> Task<Result<CompletionResponse>> {
22514    let languages = buffer.read(cx).languages_at(buffer_position);
22515    let snippet_store = project.snippets().read(cx);
22516
22517    let scopes: Vec<_> = languages
22518        .iter()
22519        .filter_map(|language| {
22520            let language_name = language.lsp_id();
22521            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22522
22523            if snippets.is_empty() {
22524                None
22525            } else {
22526                Some((language.default_scope(), snippets))
22527            }
22528        })
22529        .collect();
22530
22531    if scopes.is_empty() {
22532        return Task::ready(Ok(CompletionResponse {
22533            completions: vec![],
22534            display_options: CompletionDisplayOptions::default(),
22535            is_incomplete: false,
22536        }));
22537    }
22538
22539    let snapshot = buffer.read(cx).text_snapshot();
22540    let chars: String = snapshot
22541        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22542        .collect();
22543    let executor = cx.background_executor().clone();
22544
22545    cx.background_spawn(async move {
22546        let mut is_incomplete = false;
22547        let mut completions: Vec<Completion> = Vec::new();
22548        for (scope, snippets) in scopes.into_iter() {
22549            let classifier =
22550                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22551            let mut last_word = chars
22552                .chars()
22553                .take_while(|c| classifier.is_word(*c))
22554                .collect::<String>();
22555            last_word = last_word.chars().rev().collect();
22556
22557            if last_word.is_empty() {
22558                return Ok(CompletionResponse {
22559                    completions: vec![],
22560                    display_options: CompletionDisplayOptions::default(),
22561                    is_incomplete: true,
22562                });
22563            }
22564
22565            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22566            let to_lsp = |point: &text::Anchor| {
22567                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22568                point_to_lsp(end)
22569            };
22570            let lsp_end = to_lsp(&buffer_position);
22571
22572            let candidates = snippets
22573                .iter()
22574                .enumerate()
22575                .flat_map(|(ix, snippet)| {
22576                    snippet
22577                        .prefix
22578                        .iter()
22579                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22580                })
22581                .collect::<Vec<StringMatchCandidate>>();
22582
22583            const MAX_RESULTS: usize = 100;
22584            let mut matches = fuzzy::match_strings(
22585                &candidates,
22586                &last_word,
22587                last_word.chars().any(|c| c.is_uppercase()),
22588                true,
22589                MAX_RESULTS,
22590                &Default::default(),
22591                executor.clone(),
22592            )
22593            .await;
22594
22595            if matches.len() >= MAX_RESULTS {
22596                is_incomplete = true;
22597            }
22598
22599            // Remove all candidates where the query's start does not match the start of any word in the candidate
22600            if let Some(query_start) = last_word.chars().next() {
22601                matches.retain(|string_match| {
22602                    split_words(&string_match.string).any(|word| {
22603                        // Check that the first codepoint of the word as lowercase matches the first
22604                        // codepoint of the query as lowercase
22605                        word.chars()
22606                            .flat_map(|codepoint| codepoint.to_lowercase())
22607                            .zip(query_start.to_lowercase())
22608                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22609                    })
22610                });
22611            }
22612
22613            let matched_strings = matches
22614                .into_iter()
22615                .map(|m| m.string)
22616                .collect::<HashSet<_>>();
22617
22618            completions.extend(snippets.iter().filter_map(|snippet| {
22619                let matching_prefix = snippet
22620                    .prefix
22621                    .iter()
22622                    .find(|prefix| matched_strings.contains(*prefix))?;
22623                let start = as_offset - last_word.len();
22624                let start = snapshot.anchor_before(start);
22625                let range = start..buffer_position;
22626                let lsp_start = to_lsp(&start);
22627                let lsp_range = lsp::Range {
22628                    start: lsp_start,
22629                    end: lsp_end,
22630                };
22631                Some(Completion {
22632                    replace_range: range,
22633                    new_text: snippet.body.clone(),
22634                    source: CompletionSource::Lsp {
22635                        insert_range: None,
22636                        server_id: LanguageServerId(usize::MAX),
22637                        resolved: true,
22638                        lsp_completion: Box::new(lsp::CompletionItem {
22639                            label: snippet.prefix.first().unwrap().clone(),
22640                            kind: Some(CompletionItemKind::SNIPPET),
22641                            label_details: snippet.description.as_ref().map(|description| {
22642                                lsp::CompletionItemLabelDetails {
22643                                    detail: Some(description.clone()),
22644                                    description: None,
22645                                }
22646                            }),
22647                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22648                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22649                                lsp::InsertReplaceEdit {
22650                                    new_text: snippet.body.clone(),
22651                                    insert: lsp_range,
22652                                    replace: lsp_range,
22653                                },
22654                            )),
22655                            filter_text: Some(snippet.body.clone()),
22656                            sort_text: Some(char::MAX.to_string()),
22657                            ..lsp::CompletionItem::default()
22658                        }),
22659                        lsp_defaults: None,
22660                    },
22661                    label: CodeLabel {
22662                        text: matching_prefix.clone(),
22663                        runs: Vec::new(),
22664                        filter_range: 0..matching_prefix.len(),
22665                    },
22666                    icon_path: None,
22667                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22668                        single_line: snippet.name.clone().into(),
22669                        plain_text: snippet
22670                            .description
22671                            .clone()
22672                            .map(|description| description.into()),
22673                    }),
22674                    insert_text_mode: None,
22675                    confirm: None,
22676                })
22677            }))
22678        }
22679
22680        Ok(CompletionResponse {
22681            completions,
22682            display_options: CompletionDisplayOptions::default(),
22683            is_incomplete,
22684        })
22685    })
22686}
22687
22688impl CompletionProvider for Entity<Project> {
22689    fn completions(
22690        &self,
22691        _excerpt_id: ExcerptId,
22692        buffer: &Entity<Buffer>,
22693        buffer_position: text::Anchor,
22694        options: CompletionContext,
22695        _window: &mut Window,
22696        cx: &mut Context<Editor>,
22697    ) -> Task<Result<Vec<CompletionResponse>>> {
22698        self.update(cx, |project, cx| {
22699            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22700            let project_completions = project.completions(buffer, buffer_position, options, cx);
22701            cx.background_spawn(async move {
22702                let mut responses = project_completions.await?;
22703                let snippets = snippets.await?;
22704                if !snippets.completions.is_empty() {
22705                    responses.push(snippets);
22706                }
22707                Ok(responses)
22708            })
22709        })
22710    }
22711
22712    fn resolve_completions(
22713        &self,
22714        buffer: Entity<Buffer>,
22715        completion_indices: Vec<usize>,
22716        completions: Rc<RefCell<Box<[Completion]>>>,
22717        cx: &mut Context<Editor>,
22718    ) -> Task<Result<bool>> {
22719        self.update(cx, |project, cx| {
22720            project.lsp_store().update(cx, |lsp_store, cx| {
22721                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22722            })
22723        })
22724    }
22725
22726    fn apply_additional_edits_for_completion(
22727        &self,
22728        buffer: Entity<Buffer>,
22729        completions: Rc<RefCell<Box<[Completion]>>>,
22730        completion_index: usize,
22731        push_to_history: bool,
22732        cx: &mut Context<Editor>,
22733    ) -> Task<Result<Option<language::Transaction>>> {
22734        self.update(cx, |project, cx| {
22735            project.lsp_store().update(cx, |lsp_store, cx| {
22736                lsp_store.apply_additional_edits_for_completion(
22737                    buffer,
22738                    completions,
22739                    completion_index,
22740                    push_to_history,
22741                    cx,
22742                )
22743            })
22744        })
22745    }
22746
22747    fn is_completion_trigger(
22748        &self,
22749        buffer: &Entity<Buffer>,
22750        position: language::Anchor,
22751        text: &str,
22752        trigger_in_words: bool,
22753        menu_is_open: bool,
22754        cx: &mut Context<Editor>,
22755    ) -> bool {
22756        let mut chars = text.chars();
22757        let char = if let Some(char) = chars.next() {
22758            char
22759        } else {
22760            return false;
22761        };
22762        if chars.next().is_some() {
22763            return false;
22764        }
22765
22766        let buffer = buffer.read(cx);
22767        let snapshot = buffer.snapshot();
22768        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22769            return false;
22770        }
22771        let classifier = snapshot
22772            .char_classifier_at(position)
22773            .scope_context(Some(CharScopeContext::Completion));
22774        if trigger_in_words && classifier.is_word(char) {
22775            return true;
22776        }
22777
22778        buffer.completion_triggers().contains(text)
22779    }
22780}
22781
22782impl SemanticsProvider for Entity<Project> {
22783    fn hover(
22784        &self,
22785        buffer: &Entity<Buffer>,
22786        position: text::Anchor,
22787        cx: &mut App,
22788    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22789        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22790    }
22791
22792    fn document_highlights(
22793        &self,
22794        buffer: &Entity<Buffer>,
22795        position: text::Anchor,
22796        cx: &mut App,
22797    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22798        Some(self.update(cx, |project, cx| {
22799            project.document_highlights(buffer, position, cx)
22800        }))
22801    }
22802
22803    fn definitions(
22804        &self,
22805        buffer: &Entity<Buffer>,
22806        position: text::Anchor,
22807        kind: GotoDefinitionKind,
22808        cx: &mut App,
22809    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22810        Some(self.update(cx, |project, cx| match kind {
22811            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22812            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22813            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22814            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22815        }))
22816    }
22817
22818    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22819        self.update(cx, |project, cx| {
22820            if project
22821                .active_debug_session(cx)
22822                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22823            {
22824                return true;
22825            }
22826
22827            buffer.update(cx, |buffer, cx| {
22828                project.any_language_server_supports_inlay_hints(buffer, cx)
22829            })
22830        })
22831    }
22832
22833    fn inline_values(
22834        &self,
22835        buffer_handle: Entity<Buffer>,
22836        range: Range<text::Anchor>,
22837        cx: &mut App,
22838    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22839        self.update(cx, |project, cx| {
22840            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22841
22842            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22843        })
22844    }
22845
22846    fn inlay_hints(
22847        &self,
22848        buffer_handle: Entity<Buffer>,
22849        range: Range<text::Anchor>,
22850        cx: &mut App,
22851    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22852        Some(self.update(cx, |project, cx| {
22853            project.inlay_hints(buffer_handle, range, cx)
22854        }))
22855    }
22856
22857    fn resolve_inlay_hint(
22858        &self,
22859        hint: InlayHint,
22860        buffer_handle: Entity<Buffer>,
22861        server_id: LanguageServerId,
22862        cx: &mut App,
22863    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22864        Some(self.update(cx, |project, cx| {
22865            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22866        }))
22867    }
22868
22869    fn range_for_rename(
22870        &self,
22871        buffer: &Entity<Buffer>,
22872        position: text::Anchor,
22873        cx: &mut App,
22874    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22875        Some(self.update(cx, |project, cx| {
22876            let buffer = buffer.clone();
22877            let task = project.prepare_rename(buffer.clone(), position, cx);
22878            cx.spawn(async move |_, cx| {
22879                Ok(match task.await? {
22880                    PrepareRenameResponse::Success(range) => Some(range),
22881                    PrepareRenameResponse::InvalidPosition => None,
22882                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22883                        // Fallback on using TreeSitter info to determine identifier range
22884                        buffer.read_with(cx, |buffer, _| {
22885                            let snapshot = buffer.snapshot();
22886                            let (range, kind) = snapshot.surrounding_word(position, None);
22887                            if kind != Some(CharKind::Word) {
22888                                return None;
22889                            }
22890                            Some(
22891                                snapshot.anchor_before(range.start)
22892                                    ..snapshot.anchor_after(range.end),
22893                            )
22894                        })?
22895                    }
22896                })
22897            })
22898        }))
22899    }
22900
22901    fn perform_rename(
22902        &self,
22903        buffer: &Entity<Buffer>,
22904        position: text::Anchor,
22905        new_name: String,
22906        cx: &mut App,
22907    ) -> Option<Task<Result<ProjectTransaction>>> {
22908        Some(self.update(cx, |project, cx| {
22909            project.perform_rename(buffer.clone(), position, new_name, cx)
22910        }))
22911    }
22912}
22913
22914fn inlay_hint_settings(
22915    location: Anchor,
22916    snapshot: &MultiBufferSnapshot,
22917    cx: &mut Context<Editor>,
22918) -> InlayHintSettings {
22919    let file = snapshot.file_at(location);
22920    let language = snapshot.language_at(location).map(|l| l.name());
22921    language_settings(language, file, cx).inlay_hints
22922}
22923
22924fn consume_contiguous_rows(
22925    contiguous_row_selections: &mut Vec<Selection<Point>>,
22926    selection: &Selection<Point>,
22927    display_map: &DisplaySnapshot,
22928    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22929) -> (MultiBufferRow, MultiBufferRow) {
22930    contiguous_row_selections.push(selection.clone());
22931    let start_row = starting_row(selection, display_map);
22932    let mut end_row = ending_row(selection, display_map);
22933
22934    while let Some(next_selection) = selections.peek() {
22935        if next_selection.start.row <= end_row.0 {
22936            end_row = ending_row(next_selection, display_map);
22937            contiguous_row_selections.push(selections.next().unwrap().clone());
22938        } else {
22939            break;
22940        }
22941    }
22942    (start_row, end_row)
22943}
22944
22945fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22946    if selection.start.column > 0 {
22947        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22948    } else {
22949        MultiBufferRow(selection.start.row)
22950    }
22951}
22952
22953fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22954    if next_selection.end.column > 0 || next_selection.is_empty() {
22955        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22956    } else {
22957        MultiBufferRow(next_selection.end.row)
22958    }
22959}
22960
22961impl EditorSnapshot {
22962    pub fn remote_selections_in_range<'a>(
22963        &'a self,
22964        range: &'a Range<Anchor>,
22965        collaboration_hub: &dyn CollaborationHub,
22966        cx: &'a App,
22967    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22968        let participant_names = collaboration_hub.user_names(cx);
22969        let participant_indices = collaboration_hub.user_participant_indices(cx);
22970        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22971        let collaborators_by_replica_id = collaborators_by_peer_id
22972            .values()
22973            .map(|collaborator| (collaborator.replica_id, collaborator))
22974            .collect::<HashMap<_, _>>();
22975        self.buffer_snapshot
22976            .selections_in_range(range, false)
22977            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22978                if replica_id == AGENT_REPLICA_ID {
22979                    Some(RemoteSelection {
22980                        replica_id,
22981                        selection,
22982                        cursor_shape,
22983                        line_mode,
22984                        collaborator_id: CollaboratorId::Agent,
22985                        user_name: Some("Agent".into()),
22986                        color: cx.theme().players().agent(),
22987                    })
22988                } else {
22989                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22990                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22991                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22992                    Some(RemoteSelection {
22993                        replica_id,
22994                        selection,
22995                        cursor_shape,
22996                        line_mode,
22997                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22998                        user_name,
22999                        color: if let Some(index) = participant_index {
23000                            cx.theme().players().color_for_participant(index.0)
23001                        } else {
23002                            cx.theme().players().absent()
23003                        },
23004                    })
23005                }
23006            })
23007    }
23008
23009    pub fn hunks_for_ranges(
23010        &self,
23011        ranges: impl IntoIterator<Item = Range<Point>>,
23012    ) -> Vec<MultiBufferDiffHunk> {
23013        let mut hunks = Vec::new();
23014        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23015            HashMap::default();
23016        for query_range in ranges {
23017            let query_rows =
23018                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23019            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23020                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23021            ) {
23022                // Include deleted hunks that are adjacent to the query range, because
23023                // otherwise they would be missed.
23024                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23025                if hunk.status().is_deleted() {
23026                    intersects_range |= hunk.row_range.start == query_rows.end;
23027                    intersects_range |= hunk.row_range.end == query_rows.start;
23028                }
23029                if intersects_range {
23030                    if !processed_buffer_rows
23031                        .entry(hunk.buffer_id)
23032                        .or_default()
23033                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23034                    {
23035                        continue;
23036                    }
23037                    hunks.push(hunk);
23038                }
23039            }
23040        }
23041
23042        hunks
23043    }
23044
23045    fn display_diff_hunks_for_rows<'a>(
23046        &'a self,
23047        display_rows: Range<DisplayRow>,
23048        folded_buffers: &'a HashSet<BufferId>,
23049    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23050        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23051        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23052
23053        self.buffer_snapshot
23054            .diff_hunks_in_range(buffer_start..buffer_end)
23055            .filter_map(|hunk| {
23056                if folded_buffers.contains(&hunk.buffer_id) {
23057                    return None;
23058                }
23059
23060                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23061                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23062
23063                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23064                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23065
23066                let display_hunk = if hunk_display_start.column() != 0 {
23067                    DisplayDiffHunk::Folded {
23068                        display_row: hunk_display_start.row(),
23069                    }
23070                } else {
23071                    let mut end_row = hunk_display_end.row();
23072                    if hunk_display_end.column() > 0 {
23073                        end_row.0 += 1;
23074                    }
23075                    let is_created_file = hunk.is_created_file();
23076                    DisplayDiffHunk::Unfolded {
23077                        status: hunk.status(),
23078                        diff_base_byte_range: hunk.diff_base_byte_range,
23079                        display_row_range: hunk_display_start.row()..end_row,
23080                        multi_buffer_range: Anchor::range_in_buffer(
23081                            hunk.excerpt_id,
23082                            hunk.buffer_id,
23083                            hunk.buffer_range,
23084                        ),
23085                        is_created_file,
23086                    }
23087                };
23088
23089                Some(display_hunk)
23090            })
23091    }
23092
23093    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23094        self.display_snapshot.buffer_snapshot.language_at(position)
23095    }
23096
23097    pub fn is_focused(&self) -> bool {
23098        self.is_focused
23099    }
23100
23101    pub fn placeholder_text(&self) -> Option<String> {
23102        self.placeholder_display_snapshot
23103            .as_ref()
23104            .map(|display_map| display_map.text())
23105    }
23106
23107    pub fn scroll_position(&self) -> gpui::Point<f32> {
23108        self.scroll_anchor.scroll_position(&self.display_snapshot)
23109    }
23110
23111    fn gutter_dimensions(
23112        &self,
23113        font_id: FontId,
23114        font_size: Pixels,
23115        max_line_number_width: Pixels,
23116        cx: &App,
23117    ) -> Option<GutterDimensions> {
23118        if !self.show_gutter {
23119            return None;
23120        }
23121
23122        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23123        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23124
23125        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23126            matches!(
23127                ProjectSettings::get_global(cx).git.git_gutter,
23128                GitGutterSetting::TrackedFiles
23129            )
23130        });
23131        let gutter_settings = EditorSettings::get_global(cx).gutter;
23132        let show_line_numbers = self
23133            .show_line_numbers
23134            .unwrap_or(gutter_settings.line_numbers);
23135        let line_gutter_width = if show_line_numbers {
23136            // Avoid flicker-like gutter resizes when the line number gains another digit by
23137            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23138            let min_width_for_number_on_gutter =
23139                ch_advance * gutter_settings.min_line_number_digits as f32;
23140            max_line_number_width.max(min_width_for_number_on_gutter)
23141        } else {
23142            0.0.into()
23143        };
23144
23145        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23146        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23147
23148        let git_blame_entries_width =
23149            self.git_blame_gutter_max_author_length
23150                .map(|max_author_length| {
23151                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23152                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23153
23154                    /// The number of characters to dedicate to gaps and margins.
23155                    const SPACING_WIDTH: usize = 4;
23156
23157                    let max_char_count = max_author_length.min(renderer.max_author_length())
23158                        + ::git::SHORT_SHA_LENGTH
23159                        + MAX_RELATIVE_TIMESTAMP.len()
23160                        + SPACING_WIDTH;
23161
23162                    ch_advance * max_char_count
23163                });
23164
23165        let is_singleton = self.buffer_snapshot.is_singleton();
23166
23167        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23168        left_padding += if !is_singleton {
23169            ch_width * 4.0
23170        } else if show_runnables || show_breakpoints {
23171            ch_width * 3.0
23172        } else if show_git_gutter && show_line_numbers {
23173            ch_width * 2.0
23174        } else if show_git_gutter || show_line_numbers {
23175            ch_width
23176        } else {
23177            px(0.)
23178        };
23179
23180        let shows_folds = is_singleton && gutter_settings.folds;
23181
23182        let right_padding = if shows_folds && show_line_numbers {
23183            ch_width * 4.0
23184        } else if shows_folds || (!is_singleton && show_line_numbers) {
23185            ch_width * 3.0
23186        } else if show_line_numbers {
23187            ch_width
23188        } else {
23189            px(0.)
23190        };
23191
23192        Some(GutterDimensions {
23193            left_padding,
23194            right_padding,
23195            width: line_gutter_width + left_padding + right_padding,
23196            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23197            git_blame_entries_width,
23198        })
23199    }
23200
23201    pub fn render_crease_toggle(
23202        &self,
23203        buffer_row: MultiBufferRow,
23204        row_contains_cursor: bool,
23205        editor: Entity<Editor>,
23206        window: &mut Window,
23207        cx: &mut App,
23208    ) -> Option<AnyElement> {
23209        let folded = self.is_line_folded(buffer_row);
23210        let mut is_foldable = false;
23211
23212        if let Some(crease) = self
23213            .crease_snapshot
23214            .query_row(buffer_row, &self.buffer_snapshot)
23215        {
23216            is_foldable = true;
23217            match crease {
23218                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23219                    if let Some(render_toggle) = render_toggle {
23220                        let toggle_callback =
23221                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23222                                if folded {
23223                                    editor.update(cx, |editor, cx| {
23224                                        editor.fold_at(buffer_row, window, cx)
23225                                    });
23226                                } else {
23227                                    editor.update(cx, |editor, cx| {
23228                                        editor.unfold_at(buffer_row, window, cx)
23229                                    });
23230                                }
23231                            });
23232                        return Some((render_toggle)(
23233                            buffer_row,
23234                            folded,
23235                            toggle_callback,
23236                            window,
23237                            cx,
23238                        ));
23239                    }
23240                }
23241            }
23242        }
23243
23244        is_foldable |= self.starts_indent(buffer_row);
23245
23246        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23247            Some(
23248                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23249                    .toggle_state(folded)
23250                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23251                        if folded {
23252                            this.unfold_at(buffer_row, window, cx);
23253                        } else {
23254                            this.fold_at(buffer_row, window, cx);
23255                        }
23256                    }))
23257                    .into_any_element(),
23258            )
23259        } else {
23260            None
23261        }
23262    }
23263
23264    pub fn render_crease_trailer(
23265        &self,
23266        buffer_row: MultiBufferRow,
23267        window: &mut Window,
23268        cx: &mut App,
23269    ) -> Option<AnyElement> {
23270        let folded = self.is_line_folded(buffer_row);
23271        if let Crease::Inline { render_trailer, .. } = self
23272            .crease_snapshot
23273            .query_row(buffer_row, &self.buffer_snapshot)?
23274        {
23275            let render_trailer = render_trailer.as_ref()?;
23276            Some(render_trailer(buffer_row, folded, window, cx))
23277        } else {
23278            None
23279        }
23280    }
23281}
23282
23283impl Deref for EditorSnapshot {
23284    type Target = DisplaySnapshot;
23285
23286    fn deref(&self) -> &Self::Target {
23287        &self.display_snapshot
23288    }
23289}
23290
23291#[derive(Clone, Debug, PartialEq, Eq)]
23292pub enum EditorEvent {
23293    InputIgnored {
23294        text: Arc<str>,
23295    },
23296    InputHandled {
23297        utf16_range_to_replace: Option<Range<isize>>,
23298        text: Arc<str>,
23299    },
23300    ExcerptsAdded {
23301        buffer: Entity<Buffer>,
23302        predecessor: ExcerptId,
23303        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23304    },
23305    ExcerptsRemoved {
23306        ids: Vec<ExcerptId>,
23307        removed_buffer_ids: Vec<BufferId>,
23308    },
23309    BufferFoldToggled {
23310        ids: Vec<ExcerptId>,
23311        folded: bool,
23312    },
23313    ExcerptsEdited {
23314        ids: Vec<ExcerptId>,
23315    },
23316    ExcerptsExpanded {
23317        ids: Vec<ExcerptId>,
23318    },
23319    BufferEdited,
23320    Edited {
23321        transaction_id: clock::Lamport,
23322    },
23323    Reparsed(BufferId),
23324    Focused,
23325    FocusedIn,
23326    Blurred,
23327    DirtyChanged,
23328    Saved,
23329    TitleChanged,
23330    SelectionsChanged {
23331        local: bool,
23332    },
23333    ScrollPositionChanged {
23334        local: bool,
23335        autoscroll: bool,
23336    },
23337    TransactionUndone {
23338        transaction_id: clock::Lamport,
23339    },
23340    TransactionBegun {
23341        transaction_id: clock::Lamport,
23342    },
23343    CursorShapeChanged,
23344    BreadcrumbsChanged,
23345    PushedToNavHistory {
23346        anchor: Anchor,
23347        is_deactivate: bool,
23348    },
23349}
23350
23351impl EventEmitter<EditorEvent> for Editor {}
23352
23353impl Focusable for Editor {
23354    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23355        self.focus_handle.clone()
23356    }
23357}
23358
23359impl Render for Editor {
23360    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23361        let settings = ThemeSettings::get_global(cx);
23362
23363        let mut text_style = match self.mode {
23364            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23365                color: cx.theme().colors().editor_foreground,
23366                font_family: settings.ui_font.family.clone(),
23367                font_features: settings.ui_font.features.clone(),
23368                font_fallbacks: settings.ui_font.fallbacks.clone(),
23369                font_size: rems(0.875).into(),
23370                font_weight: settings.ui_font.weight,
23371                line_height: relative(settings.buffer_line_height.value()),
23372                ..Default::default()
23373            },
23374            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23375                color: cx.theme().colors().editor_foreground,
23376                font_family: settings.buffer_font.family.clone(),
23377                font_features: settings.buffer_font.features.clone(),
23378                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23379                font_size: settings.buffer_font_size(cx).into(),
23380                font_weight: settings.buffer_font.weight,
23381                line_height: relative(settings.buffer_line_height.value()),
23382                ..Default::default()
23383            },
23384        };
23385        if let Some(text_style_refinement) = &self.text_style_refinement {
23386            text_style.refine(text_style_refinement)
23387        }
23388
23389        let background = match self.mode {
23390            EditorMode::SingleLine => cx.theme().system().transparent,
23391            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23392            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23393            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23394        };
23395
23396        EditorElement::new(
23397            &cx.entity(),
23398            EditorStyle {
23399                background,
23400                border: cx.theme().colors().border,
23401                local_player: cx.theme().players().local(),
23402                text: text_style,
23403                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23404                syntax: cx.theme().syntax().clone(),
23405                status: cx.theme().status().clone(),
23406                inlay_hints_style: make_inlay_hints_style(cx),
23407                edit_prediction_styles: make_suggestion_styles(cx),
23408                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23409                show_underlines: self.diagnostics_enabled(),
23410            },
23411        )
23412    }
23413}
23414
23415impl EntityInputHandler for Editor {
23416    fn text_for_range(
23417        &mut self,
23418        range_utf16: Range<usize>,
23419        adjusted_range: &mut Option<Range<usize>>,
23420        _: &mut Window,
23421        cx: &mut Context<Self>,
23422    ) -> Option<String> {
23423        let snapshot = self.buffer.read(cx).read(cx);
23424        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23425        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23426        if (start.0..end.0) != range_utf16 {
23427            adjusted_range.replace(start.0..end.0);
23428        }
23429        Some(snapshot.text_for_range(start..end).collect())
23430    }
23431
23432    fn selected_text_range(
23433        &mut self,
23434        ignore_disabled_input: bool,
23435        _: &mut Window,
23436        cx: &mut Context<Self>,
23437    ) -> Option<UTF16Selection> {
23438        // Prevent the IME menu from appearing when holding down an alphabetic key
23439        // while input is disabled.
23440        if !ignore_disabled_input && !self.input_enabled {
23441            return None;
23442        }
23443
23444        let selection = self.selections.newest::<OffsetUtf16>(cx);
23445        let range = selection.range();
23446
23447        Some(UTF16Selection {
23448            range: range.start.0..range.end.0,
23449            reversed: selection.reversed,
23450        })
23451    }
23452
23453    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23454        let snapshot = self.buffer.read(cx).read(cx);
23455        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23456        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23457    }
23458
23459    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23460        self.clear_highlights::<InputComposition>(cx);
23461        self.ime_transaction.take();
23462    }
23463
23464    fn replace_text_in_range(
23465        &mut self,
23466        range_utf16: Option<Range<usize>>,
23467        text: &str,
23468        window: &mut Window,
23469        cx: &mut Context<Self>,
23470    ) {
23471        if !self.input_enabled {
23472            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23473            return;
23474        }
23475
23476        self.transact(window, cx, |this, window, cx| {
23477            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23478                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23479                Some(this.selection_replacement_ranges(range_utf16, cx))
23480            } else {
23481                this.marked_text_ranges(cx)
23482            };
23483
23484            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23485                let newest_selection_id = this.selections.newest_anchor().id;
23486                this.selections
23487                    .all::<OffsetUtf16>(cx)
23488                    .iter()
23489                    .zip(ranges_to_replace.iter())
23490                    .find_map(|(selection, range)| {
23491                        if selection.id == newest_selection_id {
23492                            Some(
23493                                (range.start.0 as isize - selection.head().0 as isize)
23494                                    ..(range.end.0 as isize - selection.head().0 as isize),
23495                            )
23496                        } else {
23497                            None
23498                        }
23499                    })
23500            });
23501
23502            cx.emit(EditorEvent::InputHandled {
23503                utf16_range_to_replace: range_to_replace,
23504                text: text.into(),
23505            });
23506
23507            if let Some(new_selected_ranges) = new_selected_ranges {
23508                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23509                    selections.select_ranges(new_selected_ranges)
23510                });
23511                this.backspace(&Default::default(), window, cx);
23512            }
23513
23514            this.handle_input(text, window, cx);
23515        });
23516
23517        if let Some(transaction) = self.ime_transaction {
23518            self.buffer.update(cx, |buffer, cx| {
23519                buffer.group_until_transaction(transaction, cx);
23520            });
23521        }
23522
23523        self.unmark_text(window, cx);
23524    }
23525
23526    fn replace_and_mark_text_in_range(
23527        &mut self,
23528        range_utf16: Option<Range<usize>>,
23529        text: &str,
23530        new_selected_range_utf16: Option<Range<usize>>,
23531        window: &mut Window,
23532        cx: &mut Context<Self>,
23533    ) {
23534        if !self.input_enabled {
23535            return;
23536        }
23537
23538        let transaction = self.transact(window, cx, |this, window, cx| {
23539            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23540                let snapshot = this.buffer.read(cx).read(cx);
23541                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23542                    for marked_range in &mut marked_ranges {
23543                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23544                        marked_range.start.0 += relative_range_utf16.start;
23545                        marked_range.start =
23546                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23547                        marked_range.end =
23548                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23549                    }
23550                }
23551                Some(marked_ranges)
23552            } else if let Some(range_utf16) = range_utf16 {
23553                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23554                Some(this.selection_replacement_ranges(range_utf16, cx))
23555            } else {
23556                None
23557            };
23558
23559            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23560                let newest_selection_id = this.selections.newest_anchor().id;
23561                this.selections
23562                    .all::<OffsetUtf16>(cx)
23563                    .iter()
23564                    .zip(ranges_to_replace.iter())
23565                    .find_map(|(selection, range)| {
23566                        if selection.id == newest_selection_id {
23567                            Some(
23568                                (range.start.0 as isize - selection.head().0 as isize)
23569                                    ..(range.end.0 as isize - selection.head().0 as isize),
23570                            )
23571                        } else {
23572                            None
23573                        }
23574                    })
23575            });
23576
23577            cx.emit(EditorEvent::InputHandled {
23578                utf16_range_to_replace: range_to_replace,
23579                text: text.into(),
23580            });
23581
23582            if let Some(ranges) = ranges_to_replace {
23583                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23584                    s.select_ranges(ranges)
23585                });
23586            }
23587
23588            let marked_ranges = {
23589                let snapshot = this.buffer.read(cx).read(cx);
23590                this.selections
23591                    .disjoint_anchors_arc()
23592                    .iter()
23593                    .map(|selection| {
23594                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23595                    })
23596                    .collect::<Vec<_>>()
23597            };
23598
23599            if text.is_empty() {
23600                this.unmark_text(window, cx);
23601            } else {
23602                this.highlight_text::<InputComposition>(
23603                    marked_ranges.clone(),
23604                    HighlightStyle {
23605                        underline: Some(UnderlineStyle {
23606                            thickness: px(1.),
23607                            color: None,
23608                            wavy: false,
23609                        }),
23610                        ..Default::default()
23611                    },
23612                    cx,
23613                );
23614            }
23615
23616            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23617            let use_autoclose = this.use_autoclose;
23618            let use_auto_surround = this.use_auto_surround;
23619            this.set_use_autoclose(false);
23620            this.set_use_auto_surround(false);
23621            this.handle_input(text, window, cx);
23622            this.set_use_autoclose(use_autoclose);
23623            this.set_use_auto_surround(use_auto_surround);
23624
23625            if let Some(new_selected_range) = new_selected_range_utf16 {
23626                let snapshot = this.buffer.read(cx).read(cx);
23627                let new_selected_ranges = marked_ranges
23628                    .into_iter()
23629                    .map(|marked_range| {
23630                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23631                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23632                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23633                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23634                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23635                    })
23636                    .collect::<Vec<_>>();
23637
23638                drop(snapshot);
23639                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23640                    selections.select_ranges(new_selected_ranges)
23641                });
23642            }
23643        });
23644
23645        self.ime_transaction = self.ime_transaction.or(transaction);
23646        if let Some(transaction) = self.ime_transaction {
23647            self.buffer.update(cx, |buffer, cx| {
23648                buffer.group_until_transaction(transaction, cx);
23649            });
23650        }
23651
23652        if self.text_highlights::<InputComposition>(cx).is_none() {
23653            self.ime_transaction.take();
23654        }
23655    }
23656
23657    fn bounds_for_range(
23658        &mut self,
23659        range_utf16: Range<usize>,
23660        element_bounds: gpui::Bounds<Pixels>,
23661        window: &mut Window,
23662        cx: &mut Context<Self>,
23663    ) -> Option<gpui::Bounds<Pixels>> {
23664        let text_layout_details = self.text_layout_details(window);
23665        let CharacterDimensions {
23666            em_width,
23667            em_advance,
23668            line_height,
23669        } = self.character_dimensions(window);
23670
23671        let snapshot = self.snapshot(window, cx);
23672        let scroll_position = snapshot.scroll_position();
23673        let scroll_left = scroll_position.x * em_advance;
23674
23675        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23676        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23677            + self.gutter_dimensions.full_width();
23678        let y = line_height * (start.row().as_f32() - scroll_position.y);
23679
23680        Some(Bounds {
23681            origin: element_bounds.origin + point(x, y),
23682            size: size(em_width, line_height),
23683        })
23684    }
23685
23686    fn character_index_for_point(
23687        &mut self,
23688        point: gpui::Point<Pixels>,
23689        _window: &mut Window,
23690        _cx: &mut Context<Self>,
23691    ) -> Option<usize> {
23692        let position_map = self.last_position_map.as_ref()?;
23693        if !position_map.text_hitbox.contains(&point) {
23694            return None;
23695        }
23696        let display_point = position_map.point_for_position(point).previous_valid;
23697        let anchor = position_map
23698            .snapshot
23699            .display_point_to_anchor(display_point, Bias::Left);
23700        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23701        Some(utf16_offset.0)
23702    }
23703}
23704
23705trait SelectionExt {
23706    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23707    fn spanned_rows(
23708        &self,
23709        include_end_if_at_line_start: bool,
23710        map: &DisplaySnapshot,
23711    ) -> Range<MultiBufferRow>;
23712}
23713
23714impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23715    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23716        let start = self
23717            .start
23718            .to_point(&map.buffer_snapshot)
23719            .to_display_point(map);
23720        let end = self
23721            .end
23722            .to_point(&map.buffer_snapshot)
23723            .to_display_point(map);
23724        if self.reversed {
23725            end..start
23726        } else {
23727            start..end
23728        }
23729    }
23730
23731    fn spanned_rows(
23732        &self,
23733        include_end_if_at_line_start: bool,
23734        map: &DisplaySnapshot,
23735    ) -> Range<MultiBufferRow> {
23736        let start = self.start.to_point(&map.buffer_snapshot);
23737        let mut end = self.end.to_point(&map.buffer_snapshot);
23738        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23739            end.row -= 1;
23740        }
23741
23742        let buffer_start = map.prev_line_boundary(start).0;
23743        let buffer_end = map.next_line_boundary(end).0;
23744        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23745    }
23746}
23747
23748impl<T: InvalidationRegion> InvalidationStack<T> {
23749    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23750    where
23751        S: Clone + ToOffset,
23752    {
23753        while let Some(region) = self.last() {
23754            let all_selections_inside_invalidation_ranges =
23755                if selections.len() == region.ranges().len() {
23756                    selections
23757                        .iter()
23758                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23759                        .all(|(selection, invalidation_range)| {
23760                            let head = selection.head().to_offset(buffer);
23761                            invalidation_range.start <= head && invalidation_range.end >= head
23762                        })
23763                } else {
23764                    false
23765                };
23766
23767            if all_selections_inside_invalidation_ranges {
23768                break;
23769            } else {
23770                self.pop();
23771            }
23772        }
23773    }
23774}
23775
23776impl<T> Default for InvalidationStack<T> {
23777    fn default() -> Self {
23778        Self(Default::default())
23779    }
23780}
23781
23782impl<T> Deref for InvalidationStack<T> {
23783    type Target = Vec<T>;
23784
23785    fn deref(&self) -> &Self::Target {
23786        &self.0
23787    }
23788}
23789
23790impl<T> DerefMut for InvalidationStack<T> {
23791    fn deref_mut(&mut self) -> &mut Self::Target {
23792        &mut self.0
23793    }
23794}
23795
23796impl InvalidationRegion for SnippetState {
23797    fn ranges(&self) -> &[Range<Anchor>] {
23798        &self.ranges[self.active_index]
23799    }
23800}
23801
23802fn edit_prediction_edit_text(
23803    current_snapshot: &BufferSnapshot,
23804    edits: &[(Range<Anchor>, String)],
23805    edit_preview: &EditPreview,
23806    include_deletions: bool,
23807    cx: &App,
23808) -> HighlightedText {
23809    let edits = edits
23810        .iter()
23811        .map(|(anchor, text)| {
23812            (
23813                anchor.start.text_anchor..anchor.end.text_anchor,
23814                text.clone(),
23815            )
23816        })
23817        .collect::<Vec<_>>();
23818
23819    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23820}
23821
23822fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23823    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23824    // Just show the raw edit text with basic styling
23825    let mut text = String::new();
23826    let mut highlights = Vec::new();
23827
23828    let insertion_highlight_style = HighlightStyle {
23829        color: Some(cx.theme().colors().text),
23830        ..Default::default()
23831    };
23832
23833    for (_, edit_text) in edits {
23834        let start_offset = text.len();
23835        text.push_str(edit_text);
23836        let end_offset = text.len();
23837
23838        if start_offset < end_offset {
23839            highlights.push((start_offset..end_offset, insertion_highlight_style));
23840        }
23841    }
23842
23843    HighlightedText {
23844        text: text.into(),
23845        highlights,
23846    }
23847}
23848
23849pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23850    match severity {
23851        lsp::DiagnosticSeverity::ERROR => colors.error,
23852        lsp::DiagnosticSeverity::WARNING => colors.warning,
23853        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23854        lsp::DiagnosticSeverity::HINT => colors.info,
23855        _ => colors.ignored,
23856    }
23857}
23858
23859pub fn styled_runs_for_code_label<'a>(
23860    label: &'a CodeLabel,
23861    syntax_theme: &'a theme::SyntaxTheme,
23862) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23863    let fade_out = HighlightStyle {
23864        fade_out: Some(0.35),
23865        ..Default::default()
23866    };
23867
23868    let mut prev_end = label.filter_range.end;
23869    label
23870        .runs
23871        .iter()
23872        .enumerate()
23873        .flat_map(move |(ix, (range, highlight_id))| {
23874            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23875                style
23876            } else {
23877                return Default::default();
23878            };
23879            let muted_style = style.highlight(fade_out);
23880
23881            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23882            if range.start >= label.filter_range.end {
23883                if range.start > prev_end {
23884                    runs.push((prev_end..range.start, fade_out));
23885                }
23886                runs.push((range.clone(), muted_style));
23887            } else if range.end <= label.filter_range.end {
23888                runs.push((range.clone(), style));
23889            } else {
23890                runs.push((range.start..label.filter_range.end, style));
23891                runs.push((label.filter_range.end..range.end, muted_style));
23892            }
23893            prev_end = cmp::max(prev_end, range.end);
23894
23895            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23896                runs.push((prev_end..label.text.len(), fade_out));
23897            }
23898
23899            runs
23900        })
23901}
23902
23903pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23904    let mut prev_index = 0;
23905    let mut prev_codepoint: Option<char> = None;
23906    text.char_indices()
23907        .chain([(text.len(), '\0')])
23908        .filter_map(move |(index, codepoint)| {
23909            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23910            let is_boundary = index == text.len()
23911                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23912                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23913            if is_boundary {
23914                let chunk = &text[prev_index..index];
23915                prev_index = index;
23916                Some(chunk)
23917            } else {
23918                None
23919            }
23920        })
23921}
23922
23923pub trait RangeToAnchorExt: Sized {
23924    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23925
23926    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23927        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23928        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23929    }
23930}
23931
23932impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23933    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23934        let start_offset = self.start.to_offset(snapshot);
23935        let end_offset = self.end.to_offset(snapshot);
23936        if start_offset == end_offset {
23937            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23938        } else {
23939            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23940        }
23941    }
23942}
23943
23944pub trait RowExt {
23945    fn as_f32(&self) -> f32;
23946
23947    fn next_row(&self) -> Self;
23948
23949    fn previous_row(&self) -> Self;
23950
23951    fn minus(&self, other: Self) -> u32;
23952}
23953
23954impl RowExt for DisplayRow {
23955    fn as_f32(&self) -> f32 {
23956        self.0 as f32
23957    }
23958
23959    fn next_row(&self) -> Self {
23960        Self(self.0 + 1)
23961    }
23962
23963    fn previous_row(&self) -> Self {
23964        Self(self.0.saturating_sub(1))
23965    }
23966
23967    fn minus(&self, other: Self) -> u32 {
23968        self.0 - other.0
23969    }
23970}
23971
23972impl RowExt for MultiBufferRow {
23973    fn as_f32(&self) -> f32 {
23974        self.0 as f32
23975    }
23976
23977    fn next_row(&self) -> Self {
23978        Self(self.0 + 1)
23979    }
23980
23981    fn previous_row(&self) -> Self {
23982        Self(self.0.saturating_sub(1))
23983    }
23984
23985    fn minus(&self, other: Self) -> u32 {
23986        self.0 - other.0
23987    }
23988}
23989
23990trait RowRangeExt {
23991    type Row;
23992
23993    fn len(&self) -> usize;
23994
23995    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23996}
23997
23998impl RowRangeExt for Range<MultiBufferRow> {
23999    type Row = MultiBufferRow;
24000
24001    fn len(&self) -> usize {
24002        (self.end.0 - self.start.0) as usize
24003    }
24004
24005    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24006        (self.start.0..self.end.0).map(MultiBufferRow)
24007    }
24008}
24009
24010impl RowRangeExt for Range<DisplayRow> {
24011    type Row = DisplayRow;
24012
24013    fn len(&self) -> usize {
24014        (self.end.0 - self.start.0) as usize
24015    }
24016
24017    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24018        (self.start.0..self.end.0).map(DisplayRow)
24019    }
24020}
24021
24022/// If select range has more than one line, we
24023/// just point the cursor to range.start.
24024fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24025    if range.start.row == range.end.row {
24026        range
24027    } else {
24028        range.start..range.start
24029    }
24030}
24031pub struct KillRing(ClipboardItem);
24032impl Global for KillRing {}
24033
24034const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24035
24036enum BreakpointPromptEditAction {
24037    Log,
24038    Condition,
24039    HitCondition,
24040}
24041
24042struct BreakpointPromptEditor {
24043    pub(crate) prompt: Entity<Editor>,
24044    editor: WeakEntity<Editor>,
24045    breakpoint_anchor: Anchor,
24046    breakpoint: Breakpoint,
24047    edit_action: BreakpointPromptEditAction,
24048    block_ids: HashSet<CustomBlockId>,
24049    editor_margins: Arc<Mutex<EditorMargins>>,
24050    _subscriptions: Vec<Subscription>,
24051}
24052
24053impl BreakpointPromptEditor {
24054    const MAX_LINES: u8 = 4;
24055
24056    fn new(
24057        editor: WeakEntity<Editor>,
24058        breakpoint_anchor: Anchor,
24059        breakpoint: Breakpoint,
24060        edit_action: BreakpointPromptEditAction,
24061        window: &mut Window,
24062        cx: &mut Context<Self>,
24063    ) -> Self {
24064        let base_text = match edit_action {
24065            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24066            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24067            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24068        }
24069        .map(|msg| msg.to_string())
24070        .unwrap_or_default();
24071
24072        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24073        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24074
24075        let prompt = cx.new(|cx| {
24076            let mut prompt = Editor::new(
24077                EditorMode::AutoHeight {
24078                    min_lines: 1,
24079                    max_lines: Some(Self::MAX_LINES as usize),
24080                },
24081                buffer,
24082                None,
24083                window,
24084                cx,
24085            );
24086            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24087            prompt.set_show_cursor_when_unfocused(false, cx);
24088            prompt.set_placeholder_text(
24089                match edit_action {
24090                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24091                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24092                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24093                },
24094                window,
24095                cx,
24096            );
24097
24098            prompt
24099        });
24100
24101        Self {
24102            prompt,
24103            editor,
24104            breakpoint_anchor,
24105            breakpoint,
24106            edit_action,
24107            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24108            block_ids: Default::default(),
24109            _subscriptions: vec![],
24110        }
24111    }
24112
24113    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24114        self.block_ids.extend(block_ids)
24115    }
24116
24117    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24118        if let Some(editor) = self.editor.upgrade() {
24119            let message = self
24120                .prompt
24121                .read(cx)
24122                .buffer
24123                .read(cx)
24124                .as_singleton()
24125                .expect("A multi buffer in breakpoint prompt isn't possible")
24126                .read(cx)
24127                .as_rope()
24128                .to_string();
24129
24130            editor.update(cx, |editor, cx| {
24131                editor.edit_breakpoint_at_anchor(
24132                    self.breakpoint_anchor,
24133                    self.breakpoint.clone(),
24134                    match self.edit_action {
24135                        BreakpointPromptEditAction::Log => {
24136                            BreakpointEditAction::EditLogMessage(message.into())
24137                        }
24138                        BreakpointPromptEditAction::Condition => {
24139                            BreakpointEditAction::EditCondition(message.into())
24140                        }
24141                        BreakpointPromptEditAction::HitCondition => {
24142                            BreakpointEditAction::EditHitCondition(message.into())
24143                        }
24144                    },
24145                    cx,
24146                );
24147
24148                editor.remove_blocks(self.block_ids.clone(), None, cx);
24149                cx.focus_self(window);
24150            });
24151        }
24152    }
24153
24154    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24155        self.editor
24156            .update(cx, |editor, cx| {
24157                editor.remove_blocks(self.block_ids.clone(), None, cx);
24158                window.focus(&editor.focus_handle);
24159            })
24160            .log_err();
24161    }
24162
24163    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24164        let settings = ThemeSettings::get_global(cx);
24165        let text_style = TextStyle {
24166            color: if self.prompt.read(cx).read_only(cx) {
24167                cx.theme().colors().text_disabled
24168            } else {
24169                cx.theme().colors().text
24170            },
24171            font_family: settings.buffer_font.family.clone(),
24172            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24173            font_size: settings.buffer_font_size(cx).into(),
24174            font_weight: settings.buffer_font.weight,
24175            line_height: relative(settings.buffer_line_height.value()),
24176            ..Default::default()
24177        };
24178        EditorElement::new(
24179            &self.prompt,
24180            EditorStyle {
24181                background: cx.theme().colors().editor_background,
24182                local_player: cx.theme().players().local(),
24183                text: text_style,
24184                ..Default::default()
24185            },
24186        )
24187    }
24188}
24189
24190impl Render for BreakpointPromptEditor {
24191    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24192        let editor_margins = *self.editor_margins.lock();
24193        let gutter_dimensions = editor_margins.gutter;
24194        h_flex()
24195            .key_context("Editor")
24196            .bg(cx.theme().colors().editor_background)
24197            .border_y_1()
24198            .border_color(cx.theme().status().info_border)
24199            .size_full()
24200            .py(window.line_height() / 2.5)
24201            .on_action(cx.listener(Self::confirm))
24202            .on_action(cx.listener(Self::cancel))
24203            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24204            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24205    }
24206}
24207
24208impl Focusable for BreakpointPromptEditor {
24209    fn focus_handle(&self, cx: &App) -> FocusHandle {
24210        self.prompt.focus_handle(cx)
24211    }
24212}
24213
24214fn all_edits_insertions_or_deletions(
24215    edits: &Vec<(Range<Anchor>, String)>,
24216    snapshot: &MultiBufferSnapshot,
24217) -> bool {
24218    let mut all_insertions = true;
24219    let mut all_deletions = true;
24220
24221    for (range, new_text) in edits.iter() {
24222        let range_is_empty = range.to_offset(snapshot).is_empty();
24223        let text_is_empty = new_text.is_empty();
24224
24225        if range_is_empty != text_is_empty {
24226            if range_is_empty {
24227                all_deletions = false;
24228            } else {
24229                all_insertions = false;
24230            }
24231        } else {
24232            return false;
24233        }
24234
24235        if !all_insertions && !all_deletions {
24236            return false;
24237        }
24238    }
24239    all_insertions || all_deletions
24240}
24241
24242struct MissingEditPredictionKeybindingTooltip;
24243
24244impl Render for MissingEditPredictionKeybindingTooltip {
24245    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24246        ui::tooltip_container(window, cx, |container, _, cx| {
24247            container
24248                .flex_shrink_0()
24249                .max_w_80()
24250                .min_h(rems_from_px(124.))
24251                .justify_between()
24252                .child(
24253                    v_flex()
24254                        .flex_1()
24255                        .text_ui_sm(cx)
24256                        .child(Label::new("Conflict with Accept Keybinding"))
24257                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24258                )
24259                .child(
24260                    h_flex()
24261                        .pb_1()
24262                        .gap_1()
24263                        .items_end()
24264                        .w_full()
24265                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24266                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24267                        }))
24268                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24269                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24270                        })),
24271                )
24272        })
24273    }
24274}
24275
24276#[derive(Debug, Clone, Copy, PartialEq)]
24277pub struct LineHighlight {
24278    pub background: Background,
24279    pub border: Option<gpui::Hsla>,
24280    pub include_gutter: bool,
24281    pub type_id: Option<TypeId>,
24282}
24283
24284struct LineManipulationResult {
24285    pub new_text: String,
24286    pub line_count_before: usize,
24287    pub line_count_after: usize,
24288}
24289
24290fn render_diff_hunk_controls(
24291    row: u32,
24292    status: &DiffHunkStatus,
24293    hunk_range: Range<Anchor>,
24294    is_created_file: bool,
24295    line_height: Pixels,
24296    editor: &Entity<Editor>,
24297    _window: &mut Window,
24298    cx: &mut App,
24299) -> AnyElement {
24300    h_flex()
24301        .h(line_height)
24302        .mr_1()
24303        .gap_1()
24304        .px_0p5()
24305        .pb_1()
24306        .border_x_1()
24307        .border_b_1()
24308        .border_color(cx.theme().colors().border_variant)
24309        .rounded_b_lg()
24310        .bg(cx.theme().colors().editor_background)
24311        .gap_1()
24312        .block_mouse_except_scroll()
24313        .shadow_md()
24314        .child(if status.has_secondary_hunk() {
24315            Button::new(("stage", row as u64), "Stage")
24316                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24317                .tooltip({
24318                    let focus_handle = editor.focus_handle(cx);
24319                    move |window, cx| {
24320                        Tooltip::for_action_in(
24321                            "Stage Hunk",
24322                            &::git::ToggleStaged,
24323                            &focus_handle,
24324                            window,
24325                            cx,
24326                        )
24327                    }
24328                })
24329                .on_click({
24330                    let editor = editor.clone();
24331                    move |_event, _window, cx| {
24332                        editor.update(cx, |editor, cx| {
24333                            editor.stage_or_unstage_diff_hunks(
24334                                true,
24335                                vec![hunk_range.start..hunk_range.start],
24336                                cx,
24337                            );
24338                        });
24339                    }
24340                })
24341        } else {
24342            Button::new(("unstage", row as u64), "Unstage")
24343                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24344                .tooltip({
24345                    let focus_handle = editor.focus_handle(cx);
24346                    move |window, cx| {
24347                        Tooltip::for_action_in(
24348                            "Unstage Hunk",
24349                            &::git::ToggleStaged,
24350                            &focus_handle,
24351                            window,
24352                            cx,
24353                        )
24354                    }
24355                })
24356                .on_click({
24357                    let editor = editor.clone();
24358                    move |_event, _window, cx| {
24359                        editor.update(cx, |editor, cx| {
24360                            editor.stage_or_unstage_diff_hunks(
24361                                false,
24362                                vec![hunk_range.start..hunk_range.start],
24363                                cx,
24364                            );
24365                        });
24366                    }
24367                })
24368        })
24369        .child(
24370            Button::new(("restore", row as u64), "Restore")
24371                .tooltip({
24372                    let focus_handle = editor.focus_handle(cx);
24373                    move |window, cx| {
24374                        Tooltip::for_action_in(
24375                            "Restore Hunk",
24376                            &::git::Restore,
24377                            &focus_handle,
24378                            window,
24379                            cx,
24380                        )
24381                    }
24382                })
24383                .on_click({
24384                    let editor = editor.clone();
24385                    move |_event, window, cx| {
24386                        editor.update(cx, |editor, cx| {
24387                            let snapshot = editor.snapshot(window, cx);
24388                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24389                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24390                        });
24391                    }
24392                })
24393                .disabled(is_created_file),
24394        )
24395        .when(
24396            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24397            |el| {
24398                el.child(
24399                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24400                        .shape(IconButtonShape::Square)
24401                        .icon_size(IconSize::Small)
24402                        // .disabled(!has_multiple_hunks)
24403                        .tooltip({
24404                            let focus_handle = editor.focus_handle(cx);
24405                            move |window, cx| {
24406                                Tooltip::for_action_in(
24407                                    "Next Hunk",
24408                                    &GoToHunk,
24409                                    &focus_handle,
24410                                    window,
24411                                    cx,
24412                                )
24413                            }
24414                        })
24415                        .on_click({
24416                            let editor = editor.clone();
24417                            move |_event, window, cx| {
24418                                editor.update(cx, |editor, cx| {
24419                                    let snapshot = editor.snapshot(window, cx);
24420                                    let position =
24421                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24422                                    editor.go_to_hunk_before_or_after_position(
24423                                        &snapshot,
24424                                        position,
24425                                        Direction::Next,
24426                                        window,
24427                                        cx,
24428                                    );
24429                                    editor.expand_selected_diff_hunks(cx);
24430                                });
24431                            }
24432                        }),
24433                )
24434                .child(
24435                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24436                        .shape(IconButtonShape::Square)
24437                        .icon_size(IconSize::Small)
24438                        // .disabled(!has_multiple_hunks)
24439                        .tooltip({
24440                            let focus_handle = editor.focus_handle(cx);
24441                            move |window, cx| {
24442                                Tooltip::for_action_in(
24443                                    "Previous Hunk",
24444                                    &GoToPreviousHunk,
24445                                    &focus_handle,
24446                                    window,
24447                                    cx,
24448                                )
24449                            }
24450                        })
24451                        .on_click({
24452                            let editor = editor.clone();
24453                            move |_event, window, cx| {
24454                                editor.update(cx, |editor, cx| {
24455                                    let snapshot = editor.snapshot(window, cx);
24456                                    let point =
24457                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24458                                    editor.go_to_hunk_before_or_after_position(
24459                                        &snapshot,
24460                                        point,
24461                                        Direction::Prev,
24462                                        window,
24463                                        cx,
24464                                    );
24465                                    editor.expand_selected_diff_hunks(cx);
24466                                });
24467                            }
24468                        }),
24469                )
24470            },
24471        )
24472        .into_any_element()
24473}
24474
24475pub fn multibuffer_context_lines(cx: &App) -> u32 {
24476    EditorSettings::try_get(cx)
24477        .map(|settings| settings.excerpt_context_lines)
24478        .unwrap_or(2)
24479        .min(32)
24480}