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 element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::{AGENT_REPLICA_ID, ReplicaId};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  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(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  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<DiagnosticEntryRef<'_, 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<DiagnosticEntryRef<'_, 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    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  742type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  743
  744#[derive(Default)]
  745struct ScrollbarMarkerState {
  746    scrollbar_size: Size<Pixels>,
  747    dirty: bool,
  748    markers: Arc<[PaintQuad]>,
  749    pending_refresh: Option<Task<Result<()>>>,
  750}
  751
  752impl ScrollbarMarkerState {
  753    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  754        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  755    }
  756}
  757
  758#[derive(Clone, Copy, PartialEq, Eq)]
  759pub enum MinimapVisibility {
  760    Disabled,
  761    Enabled {
  762        /// The configuration currently present in the users settings.
  763        setting_configuration: bool,
  764        /// Whether to override the currently set visibility from the users setting.
  765        toggle_override: bool,
  766    },
  767}
  768
  769impl MinimapVisibility {
  770    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  771        if mode.is_full() {
  772            Self::Enabled {
  773                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  774                toggle_override: false,
  775            }
  776        } else {
  777            Self::Disabled
  778        }
  779    }
  780
  781    fn hidden(&self) -> Self {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => Self::Enabled {
  787                setting_configuration,
  788                toggle_override: setting_configuration,
  789            },
  790            Self::Disabled => Self::Disabled,
  791        }
  792    }
  793
  794    fn disabled(&self) -> bool {
  795        matches!(*self, Self::Disabled)
  796    }
  797
  798    fn settings_visibility(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                ..
  803            } => setting_configuration,
  804            _ => false,
  805        }
  806    }
  807
  808    fn visible(&self) -> bool {
  809        match *self {
  810            Self::Enabled {
  811                setting_configuration,
  812                toggle_override,
  813            } => setting_configuration ^ toggle_override,
  814            _ => false,
  815        }
  816    }
  817
  818    fn toggle_visibility(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                toggle_override,
  822                setting_configuration,
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: !toggle_override,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    inlay_hint_cache: InlayHintCache,
 1127    next_inlay_id: u32,
 1128    next_color_inlay_id: u32,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    serialize_dirty_buffers: bool,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    post_scroll_update: Task<()>,
 1194    refresh_colors_task: Task<()>,
 1195    folding_newlines: Task<()>,
 1196    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1197}
 1198
 1199#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1200enum NextScrollCursorCenterTopBottom {
 1201    #[default]
 1202    Center,
 1203    Top,
 1204    Bottom,
 1205}
 1206
 1207impl NextScrollCursorCenterTopBottom {
 1208    fn next(&self) -> Self {
 1209        match self {
 1210            Self::Center => Self::Top,
 1211            Self::Top => Self::Bottom,
 1212            Self::Bottom => Self::Center,
 1213        }
 1214    }
 1215}
 1216
 1217#[derive(Clone)]
 1218pub struct EditorSnapshot {
 1219    pub mode: EditorMode,
 1220    show_gutter: bool,
 1221    show_line_numbers: Option<bool>,
 1222    show_git_diff_gutter: Option<bool>,
 1223    show_code_actions: Option<bool>,
 1224    show_runnables: Option<bool>,
 1225    show_breakpoints: Option<bool>,
 1226    git_blame_gutter_max_author_length: Option<usize>,
 1227    pub display_snapshot: DisplaySnapshot,
 1228    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1229    is_focused: bool,
 1230    scroll_anchor: ScrollAnchor,
 1231    ongoing_scroll: OngoingScroll,
 1232    current_line_highlight: CurrentLineHighlight,
 1233    gutter_hovered: bool,
 1234}
 1235
 1236#[derive(Default, Debug, Clone, Copy)]
 1237pub struct GutterDimensions {
 1238    pub left_padding: Pixels,
 1239    pub right_padding: Pixels,
 1240    pub width: Pixels,
 1241    pub margin: Pixels,
 1242    pub git_blame_entries_width: Option<Pixels>,
 1243}
 1244
 1245impl GutterDimensions {
 1246    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1247        Self {
 1248            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1249            ..Default::default()
 1250        }
 1251    }
 1252
 1253    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1254        -cx.text_system().descent(font_id, font_size)
 1255    }
 1256    /// The full width of the space taken up by the gutter.
 1257    pub fn full_width(&self) -> Pixels {
 1258        self.margin + self.width
 1259    }
 1260
 1261    /// The width of the space reserved for the fold indicators,
 1262    /// use alongside 'justify_end' and `gutter_width` to
 1263    /// right align content with the line numbers
 1264    pub fn fold_area_width(&self) -> Pixels {
 1265        self.margin + self.right_padding
 1266    }
 1267}
 1268
 1269struct CharacterDimensions {
 1270    em_width: Pixels,
 1271    em_advance: Pixels,
 1272    line_height: Pixels,
 1273}
 1274
 1275#[derive(Debug)]
 1276pub struct RemoteSelection {
 1277    pub replica_id: ReplicaId,
 1278    pub selection: Selection<Anchor>,
 1279    pub cursor_shape: CursorShape,
 1280    pub collaborator_id: CollaboratorId,
 1281    pub line_mode: bool,
 1282    pub user_name: Option<SharedString>,
 1283    pub color: PlayerColor,
 1284}
 1285
 1286#[derive(Clone, Debug)]
 1287struct SelectionHistoryEntry {
 1288    selections: Arc<[Selection<Anchor>]>,
 1289    select_next_state: Option<SelectNextState>,
 1290    select_prev_state: Option<SelectNextState>,
 1291    add_selections_state: Option<AddSelectionsState>,
 1292}
 1293
 1294#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1295enum SelectionHistoryMode {
 1296    Normal,
 1297    Undoing,
 1298    Redoing,
 1299    Skipping,
 1300}
 1301
 1302#[derive(Clone, PartialEq, Eq, Hash)]
 1303struct HoveredCursor {
 1304    replica_id: u16,
 1305    selection_id: usize,
 1306}
 1307
 1308impl Default for SelectionHistoryMode {
 1309    fn default() -> Self {
 1310        Self::Normal
 1311    }
 1312}
 1313
 1314#[derive(Debug)]
 1315/// SelectionEffects controls the side-effects of updating the selection.
 1316///
 1317/// The default behaviour does "what you mostly want":
 1318/// - it pushes to the nav history if the cursor moved by >10 lines
 1319/// - it re-triggers completion requests
 1320/// - it scrolls to fit
 1321///
 1322/// You might want to modify these behaviours. For example when doing a "jump"
 1323/// like go to definition, we always want to add to nav history; but when scrolling
 1324/// in vim mode we never do.
 1325///
 1326/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1327/// move.
 1328#[derive(Clone)]
 1329pub struct SelectionEffects {
 1330    nav_history: Option<bool>,
 1331    completions: bool,
 1332    scroll: Option<Autoscroll>,
 1333}
 1334
 1335impl Default for SelectionEffects {
 1336    fn default() -> Self {
 1337        Self {
 1338            nav_history: None,
 1339            completions: true,
 1340            scroll: Some(Autoscroll::fit()),
 1341        }
 1342    }
 1343}
 1344impl SelectionEffects {
 1345    pub fn scroll(scroll: Autoscroll) -> Self {
 1346        Self {
 1347            scroll: Some(scroll),
 1348            ..Default::default()
 1349        }
 1350    }
 1351
 1352    pub fn no_scroll() -> Self {
 1353        Self {
 1354            scroll: None,
 1355            ..Default::default()
 1356        }
 1357    }
 1358
 1359    pub fn completions(self, completions: bool) -> Self {
 1360        Self {
 1361            completions,
 1362            ..self
 1363        }
 1364    }
 1365
 1366    pub fn nav_history(self, nav_history: bool) -> Self {
 1367        Self {
 1368            nav_history: Some(nav_history),
 1369            ..self
 1370        }
 1371    }
 1372}
 1373
 1374struct DeferredSelectionEffectsState {
 1375    changed: bool,
 1376    effects: SelectionEffects,
 1377    old_cursor_position: Anchor,
 1378    history_entry: SelectionHistoryEntry,
 1379}
 1380
 1381#[derive(Default)]
 1382struct SelectionHistory {
 1383    #[allow(clippy::type_complexity)]
 1384    selections_by_transaction:
 1385        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1386    mode: SelectionHistoryMode,
 1387    undo_stack: VecDeque<SelectionHistoryEntry>,
 1388    redo_stack: VecDeque<SelectionHistoryEntry>,
 1389}
 1390
 1391impl SelectionHistory {
 1392    #[track_caller]
 1393    fn insert_transaction(
 1394        &mut self,
 1395        transaction_id: TransactionId,
 1396        selections: Arc<[Selection<Anchor>]>,
 1397    ) {
 1398        if selections.is_empty() {
 1399            log::error!(
 1400                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1401                std::panic::Location::caller()
 1402            );
 1403            return;
 1404        }
 1405        self.selections_by_transaction
 1406            .insert(transaction_id, (selections, None));
 1407    }
 1408
 1409    #[allow(clippy::type_complexity)]
 1410    fn transaction(
 1411        &self,
 1412        transaction_id: TransactionId,
 1413    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1414        self.selections_by_transaction.get(&transaction_id)
 1415    }
 1416
 1417    #[allow(clippy::type_complexity)]
 1418    fn transaction_mut(
 1419        &mut self,
 1420        transaction_id: TransactionId,
 1421    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1422        self.selections_by_transaction.get_mut(&transaction_id)
 1423    }
 1424
 1425    fn push(&mut self, entry: SelectionHistoryEntry) {
 1426        if !entry.selections.is_empty() {
 1427            match self.mode {
 1428                SelectionHistoryMode::Normal => {
 1429                    self.push_undo(entry);
 1430                    self.redo_stack.clear();
 1431                }
 1432                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1433                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1434                SelectionHistoryMode::Skipping => {}
 1435            }
 1436        }
 1437    }
 1438
 1439    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1440        if self
 1441            .undo_stack
 1442            .back()
 1443            .is_none_or(|e| e.selections != entry.selections)
 1444        {
 1445            self.undo_stack.push_back(entry);
 1446            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1447                self.undo_stack.pop_front();
 1448            }
 1449        }
 1450    }
 1451
 1452    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1453        if self
 1454            .redo_stack
 1455            .back()
 1456            .is_none_or(|e| e.selections != entry.selections)
 1457        {
 1458            self.redo_stack.push_back(entry);
 1459            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1460                self.redo_stack.pop_front();
 1461            }
 1462        }
 1463    }
 1464}
 1465
 1466#[derive(Clone, Copy)]
 1467pub struct RowHighlightOptions {
 1468    pub autoscroll: bool,
 1469    pub include_gutter: bool,
 1470}
 1471
 1472impl Default for RowHighlightOptions {
 1473    fn default() -> Self {
 1474        Self {
 1475            autoscroll: Default::default(),
 1476            include_gutter: true,
 1477        }
 1478    }
 1479}
 1480
 1481struct RowHighlight {
 1482    index: usize,
 1483    range: Range<Anchor>,
 1484    color: Hsla,
 1485    options: RowHighlightOptions,
 1486    type_id: TypeId,
 1487}
 1488
 1489#[derive(Clone, Debug)]
 1490struct AddSelectionsState {
 1491    groups: Vec<AddSelectionsGroup>,
 1492}
 1493
 1494#[derive(Clone, Debug)]
 1495struct AddSelectionsGroup {
 1496    above: bool,
 1497    stack: Vec<usize>,
 1498}
 1499
 1500#[derive(Clone)]
 1501struct SelectNextState {
 1502    query: AhoCorasick,
 1503    wordwise: bool,
 1504    done: bool,
 1505}
 1506
 1507impl std::fmt::Debug for SelectNextState {
 1508    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1509        f.debug_struct(std::any::type_name::<Self>())
 1510            .field("wordwise", &self.wordwise)
 1511            .field("done", &self.done)
 1512            .finish()
 1513    }
 1514}
 1515
 1516#[derive(Debug)]
 1517struct AutocloseRegion {
 1518    selection_id: usize,
 1519    range: Range<Anchor>,
 1520    pair: BracketPair,
 1521}
 1522
 1523#[derive(Debug)]
 1524struct SnippetState {
 1525    ranges: Vec<Vec<Range<Anchor>>>,
 1526    active_index: usize,
 1527    choices: Vec<Option<Vec<String>>>,
 1528}
 1529
 1530#[doc(hidden)]
 1531pub struct RenameState {
 1532    pub range: Range<Anchor>,
 1533    pub old_name: Arc<str>,
 1534    pub editor: Entity<Editor>,
 1535    block_id: CustomBlockId,
 1536}
 1537
 1538struct InvalidationStack<T>(Vec<T>);
 1539
 1540struct RegisteredEditPredictionProvider {
 1541    provider: Arc<dyn EditPredictionProviderHandle>,
 1542    _subscription: Subscription,
 1543}
 1544
 1545#[derive(Debug, PartialEq, Eq)]
 1546pub struct ActiveDiagnosticGroup {
 1547    pub active_range: Range<Anchor>,
 1548    pub active_message: String,
 1549    pub group_id: usize,
 1550    pub blocks: HashSet<CustomBlockId>,
 1551}
 1552
 1553#[derive(Debug, PartialEq, Eq)]
 1554
 1555pub(crate) enum ActiveDiagnostic {
 1556    None,
 1557    All,
 1558    Group(ActiveDiagnosticGroup),
 1559}
 1560
 1561#[derive(Serialize, Deserialize, Clone, Debug)]
 1562pub struct ClipboardSelection {
 1563    /// The number of bytes in this selection.
 1564    pub len: usize,
 1565    /// Whether this was a full-line selection.
 1566    pub is_entire_line: bool,
 1567    /// The indentation of the first line when this content was originally copied.
 1568    pub first_line_indent: u32,
 1569}
 1570
 1571// selections, scroll behavior, was newest selection reversed
 1572type SelectSyntaxNodeHistoryState = (
 1573    Box<[Selection<usize>]>,
 1574    SelectSyntaxNodeScrollBehavior,
 1575    bool,
 1576);
 1577
 1578#[derive(Default)]
 1579struct SelectSyntaxNodeHistory {
 1580    stack: Vec<SelectSyntaxNodeHistoryState>,
 1581    // disable temporarily to allow changing selections without losing the stack
 1582    pub disable_clearing: bool,
 1583}
 1584
 1585impl SelectSyntaxNodeHistory {
 1586    pub fn try_clear(&mut self) {
 1587        if !self.disable_clearing {
 1588            self.stack.clear();
 1589        }
 1590    }
 1591
 1592    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1593        self.stack.push(selection);
 1594    }
 1595
 1596    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1597        self.stack.pop()
 1598    }
 1599}
 1600
 1601enum SelectSyntaxNodeScrollBehavior {
 1602    CursorTop,
 1603    FitSelection,
 1604    CursorBottom,
 1605}
 1606
 1607#[derive(Debug)]
 1608pub(crate) struct NavigationData {
 1609    cursor_anchor: Anchor,
 1610    cursor_position: Point,
 1611    scroll_anchor: ScrollAnchor,
 1612    scroll_top_row: u32,
 1613}
 1614
 1615#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1616pub enum GotoDefinitionKind {
 1617    Symbol,
 1618    Declaration,
 1619    Type,
 1620    Implementation,
 1621}
 1622
 1623#[derive(Debug, Clone)]
 1624enum InlayHintRefreshReason {
 1625    ModifiersChanged(bool),
 1626    Toggle(bool),
 1627    SettingsChange(InlayHintSettings),
 1628    NewLinesShown,
 1629    BufferEdited(HashSet<Arc<Language>>),
 1630    RefreshRequested,
 1631    ExcerptsRemoved(Vec<ExcerptId>),
 1632}
 1633
 1634impl InlayHintRefreshReason {
 1635    fn description(&self) -> &'static str {
 1636        match self {
 1637            Self::ModifiersChanged(_) => "modifiers changed",
 1638            Self::Toggle(_) => "toggle",
 1639            Self::SettingsChange(_) => "settings change",
 1640            Self::NewLinesShown => "new lines shown",
 1641            Self::BufferEdited(_) => "buffer edited",
 1642            Self::RefreshRequested => "refresh requested",
 1643            Self::ExcerptsRemoved(_) => "excerpts removed",
 1644        }
 1645    }
 1646}
 1647
 1648pub enum FormatTarget {
 1649    Buffers(HashSet<Entity<Buffer>>),
 1650    Ranges(Vec<Range<MultiBufferPoint>>),
 1651}
 1652
 1653pub(crate) struct FocusedBlock {
 1654    id: BlockId,
 1655    focus_handle: WeakFocusHandle,
 1656}
 1657
 1658#[derive(Clone)]
 1659enum JumpData {
 1660    MultiBufferRow {
 1661        row: MultiBufferRow,
 1662        line_offset_from_top: u32,
 1663    },
 1664    MultiBufferPoint {
 1665        excerpt_id: ExcerptId,
 1666        position: Point,
 1667        anchor: text::Anchor,
 1668        line_offset_from_top: u32,
 1669    },
 1670}
 1671
 1672pub enum MultibufferSelectionMode {
 1673    First,
 1674    All,
 1675}
 1676
 1677#[derive(Clone, Copy, Debug, Default)]
 1678pub struct RewrapOptions {
 1679    pub override_language_settings: bool,
 1680    pub preserve_existing_whitespace: bool,
 1681}
 1682
 1683impl Editor {
 1684    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1688    }
 1689
 1690    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1691        let buffer = cx.new(|cx| Buffer::local("", cx));
 1692        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1693        Self::new(EditorMode::full(), buffer, None, window, cx)
 1694    }
 1695
 1696    pub fn auto_height(
 1697        min_lines: usize,
 1698        max_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: Some(max_lines),
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1717    /// The editor grows as tall as needed to fit its content.
 1718    pub fn auto_height_unbounded(
 1719        min_lines: usize,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| Buffer::local("", cx));
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(
 1726            EditorMode::AutoHeight {
 1727                min_lines,
 1728                max_lines: None,
 1729            },
 1730            buffer,
 1731            None,
 1732            window,
 1733            cx,
 1734        )
 1735    }
 1736
 1737    pub fn for_buffer(
 1738        buffer: Entity<Buffer>,
 1739        project: Option<Entity<Project>>,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1744        Self::new(EditorMode::full(), buffer, project, window, cx)
 1745    }
 1746
 1747    pub fn for_multibuffer(
 1748        buffer: Entity<MultiBuffer>,
 1749        project: Option<Entity<Project>>,
 1750        window: &mut Window,
 1751        cx: &mut Context<Self>,
 1752    ) -> Self {
 1753        Self::new(EditorMode::full(), buffer, project, window, cx)
 1754    }
 1755
 1756    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1757        let mut clone = Self::new(
 1758            self.mode.clone(),
 1759            self.buffer.clone(),
 1760            self.project.clone(),
 1761            window,
 1762            cx,
 1763        );
 1764        self.display_map.update(cx, |display_map, cx| {
 1765            let snapshot = display_map.snapshot(cx);
 1766            clone.display_map.update(cx, |display_map, cx| {
 1767                display_map.set_state(&snapshot, cx);
 1768            });
 1769        });
 1770        clone.folds_did_change(cx);
 1771        clone.selections.clone_state(&self.selections);
 1772        clone.scroll_manager.clone_state(&self.scroll_manager);
 1773        clone.searchable = self.searchable;
 1774        clone.read_only = self.read_only;
 1775        clone
 1776    }
 1777
 1778    pub fn new(
 1779        mode: EditorMode,
 1780        buffer: Entity<MultiBuffer>,
 1781        project: Option<Entity<Project>>,
 1782        window: &mut Window,
 1783        cx: &mut Context<Self>,
 1784    ) -> Self {
 1785        Editor::new_internal(mode, buffer, project, None, window, cx)
 1786    }
 1787
 1788    fn new_internal(
 1789        mode: EditorMode,
 1790        multi_buffer: Entity<MultiBuffer>,
 1791        project: Option<Entity<Project>>,
 1792        display_map: Option<Entity<DisplayMap>>,
 1793        window: &mut Window,
 1794        cx: &mut Context<Self>,
 1795    ) -> Self {
 1796        debug_assert!(
 1797            display_map.is_none() || mode.is_minimap(),
 1798            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1799        );
 1800
 1801        let full_mode = mode.is_full();
 1802        let is_minimap = mode.is_minimap();
 1803        let diagnostics_max_severity = if full_mode {
 1804            EditorSettings::get_global(cx)
 1805                .diagnostics_max_severity
 1806                .unwrap_or(DiagnosticSeverity::Hint)
 1807        } else {
 1808            DiagnosticSeverity::Off
 1809        };
 1810        let style = window.text_style();
 1811        let font_size = style.font_size.to_pixels(window.rem_size());
 1812        let editor = cx.entity().downgrade();
 1813        let fold_placeholder = FoldPlaceholder {
 1814            constrain_width: false,
 1815            render: Arc::new(move |fold_id, fold_range, cx| {
 1816                let editor = editor.clone();
 1817                div()
 1818                    .id(fold_id)
 1819                    .bg(cx.theme().colors().ghost_element_background)
 1820                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1821                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1822                    .rounded_xs()
 1823                    .size_full()
 1824                    .cursor_pointer()
 1825                    .child("")
 1826                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1827                    .on_click(move |_, _window, cx| {
 1828                        editor
 1829                            .update(cx, |editor, cx| {
 1830                                editor.unfold_ranges(
 1831                                    &[fold_range.start..fold_range.end],
 1832                                    true,
 1833                                    false,
 1834                                    cx,
 1835                                );
 1836                                cx.stop_propagation();
 1837                            })
 1838                            .ok();
 1839                    })
 1840                    .into_any()
 1841            }),
 1842            merge_adjacent: true,
 1843            ..FoldPlaceholder::default()
 1844        };
 1845        let display_map = display_map.unwrap_or_else(|| {
 1846            cx.new(|cx| {
 1847                DisplayMap::new(
 1848                    multi_buffer.clone(),
 1849                    style.font(),
 1850                    font_size,
 1851                    None,
 1852                    FILE_HEADER_HEIGHT,
 1853                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1854                    fold_placeholder,
 1855                    diagnostics_max_severity,
 1856                    cx,
 1857                )
 1858            })
 1859        });
 1860
 1861        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1862
 1863        let blink_manager = cx.new(|cx| {
 1864            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1865            if is_minimap {
 1866                blink_manager.disable(cx);
 1867            }
 1868            blink_manager
 1869        });
 1870
 1871        let soft_wrap_mode_override =
 1872            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1873
 1874        let mut project_subscriptions = Vec::new();
 1875        if full_mode && let Some(project) = project.as_ref() {
 1876            project_subscriptions.push(cx.subscribe_in(
 1877                project,
 1878                window,
 1879                |editor, _, event, window, cx| match event {
 1880                    project::Event::RefreshCodeLens => {
 1881                        // we always query lens with actions, without storing them, always refreshing them
 1882                    }
 1883                    project::Event::RefreshInlayHints => {
 1884                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1885                    }
 1886                    project::Event::LanguageServerAdded(..)
 1887                    | project::Event::LanguageServerRemoved(..) => {
 1888                        if editor.tasks_update_task.is_none() {
 1889                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1890                        }
 1891                    }
 1892                    project::Event::SnippetEdit(id, snippet_edits) => {
 1893                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1894                            let focus_handle = editor.focus_handle(cx);
 1895                            if focus_handle.is_focused(window) {
 1896                                let snapshot = buffer.read(cx).snapshot();
 1897                                for (range, snippet) in snippet_edits {
 1898                                    let editor_range =
 1899                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1900                                    editor
 1901                                        .insert_snippet(
 1902                                            &[editor_range],
 1903                                            snippet.clone(),
 1904                                            window,
 1905                                            cx,
 1906                                        )
 1907                                        .ok();
 1908                                }
 1909                            }
 1910                        }
 1911                    }
 1912                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1913                        let buffer_id = *buffer_id;
 1914                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1915                            let registered = editor.register_buffer(buffer_id, cx);
 1916                            if registered {
 1917                                editor.update_lsp_data(Some(buffer_id), window, cx);
 1918                                editor.refresh_inlay_hints(
 1919                                    InlayHintRefreshReason::RefreshRequested,
 1920                                    cx,
 1921                                );
 1922                                refresh_linked_ranges(editor, window, cx);
 1923                                editor.refresh_code_actions(window, cx);
 1924                                editor.refresh_document_highlights(cx);
 1925                            }
 1926                        }
 1927                    }
 1928
 1929                    project::Event::EntryRenamed(transaction) => {
 1930                        let Some(workspace) = editor.workspace() else {
 1931                            return;
 1932                        };
 1933                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1934                        else {
 1935                            return;
 1936                        };
 1937                        if active_editor.entity_id() == cx.entity_id() {
 1938                            let edited_buffers_already_open = {
 1939                                let other_editors: Vec<Entity<Editor>> = workspace
 1940                                    .read(cx)
 1941                                    .panes()
 1942                                    .iter()
 1943                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1944                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1945                                    .collect();
 1946
 1947                                transaction.0.keys().all(|buffer| {
 1948                                    other_editors.iter().any(|editor| {
 1949                                        let multi_buffer = editor.read(cx).buffer();
 1950                                        multi_buffer.read(cx).is_singleton()
 1951                                            && multi_buffer.read(cx).as_singleton().map_or(
 1952                                                false,
 1953                                                |singleton| {
 1954                                                    singleton.entity_id() == buffer.entity_id()
 1955                                                },
 1956                                            )
 1957                                    })
 1958                                })
 1959                            };
 1960
 1961                            if !edited_buffers_already_open {
 1962                                let workspace = workspace.downgrade();
 1963                                let transaction = transaction.clone();
 1964                                cx.defer_in(window, move |_, window, cx| {
 1965                                    cx.spawn_in(window, async move |editor, cx| {
 1966                                        Self::open_project_transaction(
 1967                                            &editor,
 1968                                            workspace,
 1969                                            transaction,
 1970                                            "Rename".to_string(),
 1971                                            cx,
 1972                                        )
 1973                                        .await
 1974                                        .ok()
 1975                                    })
 1976                                    .detach();
 1977                                });
 1978                            }
 1979                        }
 1980                    }
 1981
 1982                    _ => {}
 1983                },
 1984            ));
 1985            if let Some(task_inventory) = project
 1986                .read(cx)
 1987                .task_store()
 1988                .read(cx)
 1989                .task_inventory()
 1990                .cloned()
 1991            {
 1992                project_subscriptions.push(cx.observe_in(
 1993                    &task_inventory,
 1994                    window,
 1995                    |editor, _, window, cx| {
 1996                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1997                    },
 1998                ));
 1999            };
 2000
 2001            project_subscriptions.push(cx.subscribe_in(
 2002                &project.read(cx).breakpoint_store(),
 2003                window,
 2004                |editor, _, event, window, cx| match event {
 2005                    BreakpointStoreEvent::ClearDebugLines => {
 2006                        editor.clear_row_highlights::<ActiveDebugLine>();
 2007                        editor.refresh_inline_values(cx);
 2008                    }
 2009                    BreakpointStoreEvent::SetDebugLine => {
 2010                        if editor.go_to_active_debug_line(window, cx) {
 2011                            cx.stop_propagation();
 2012                        }
 2013
 2014                        editor.refresh_inline_values(cx);
 2015                    }
 2016                    _ => {}
 2017                },
 2018            ));
 2019            let git_store = project.read(cx).git_store().clone();
 2020            let project = project.clone();
 2021            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2022                if let GitStoreEvent::RepositoryUpdated(
 2023                    _,
 2024                    RepositoryEvent::Updated {
 2025                        new_instance: true, ..
 2026                    },
 2027                    _,
 2028                ) = event
 2029                {
 2030                    this.load_diff_task = Some(
 2031                        update_uncommitted_diff_for_buffer(
 2032                            cx.entity(),
 2033                            &project,
 2034                            this.buffer.read(cx).all_buffers(),
 2035                            this.buffer.clone(),
 2036                            cx,
 2037                        )
 2038                        .shared(),
 2039                    );
 2040                }
 2041            }));
 2042        }
 2043
 2044        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2045
 2046        let inlay_hint_settings =
 2047            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2048        let focus_handle = cx.focus_handle();
 2049        if !is_minimap {
 2050            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2051                .detach();
 2052            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2053                .detach();
 2054            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2055                .detach();
 2056            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2057                .detach();
 2058            cx.observe_pending_input(window, Self::observe_pending_input)
 2059                .detach();
 2060        }
 2061
 2062        let show_indent_guides =
 2063            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2064                Some(false)
 2065            } else {
 2066                None
 2067            };
 2068
 2069        let breakpoint_store = match (&mode, project.as_ref()) {
 2070            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2071            _ => None,
 2072        };
 2073
 2074        let mut code_action_providers = Vec::new();
 2075        let mut load_uncommitted_diff = None;
 2076        if let Some(project) = project.clone() {
 2077            load_uncommitted_diff = Some(
 2078                update_uncommitted_diff_for_buffer(
 2079                    cx.entity(),
 2080                    &project,
 2081                    multi_buffer.read(cx).all_buffers(),
 2082                    multi_buffer.clone(),
 2083                    cx,
 2084                )
 2085                .shared(),
 2086            );
 2087            code_action_providers.push(Rc::new(project) as Rc<_>);
 2088        }
 2089
 2090        let mut editor = Self {
 2091            focus_handle,
 2092            show_cursor_when_unfocused: false,
 2093            last_focused_descendant: None,
 2094            buffer: multi_buffer.clone(),
 2095            display_map: display_map.clone(),
 2096            placeholder_display_map: None,
 2097            selections,
 2098            scroll_manager: ScrollManager::new(cx),
 2099            columnar_selection_state: None,
 2100            add_selections_state: None,
 2101            select_next_state: None,
 2102            select_prev_state: None,
 2103            selection_history: SelectionHistory::default(),
 2104            defer_selection_effects: false,
 2105            deferred_selection_effects_state: None,
 2106            autoclose_regions: Vec::new(),
 2107            snippet_stack: InvalidationStack::default(),
 2108            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2109            ime_transaction: None,
 2110            active_diagnostics: ActiveDiagnostic::None,
 2111            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2112            inline_diagnostics_update: Task::ready(()),
 2113            inline_diagnostics: Vec::new(),
 2114            soft_wrap_mode_override,
 2115            diagnostics_max_severity,
 2116            hard_wrap: None,
 2117            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2118            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2119            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2120            project,
 2121            blink_manager: blink_manager.clone(),
 2122            show_local_selections: true,
 2123            show_scrollbars: ScrollbarAxes {
 2124                horizontal: full_mode,
 2125                vertical: full_mode,
 2126            },
 2127            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2128            offset_content: !matches!(mode, EditorMode::SingleLine),
 2129            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2130            show_gutter: full_mode,
 2131            show_line_numbers: (!full_mode).then_some(false),
 2132            use_relative_line_numbers: None,
 2133            disable_expand_excerpt_buttons: !full_mode,
 2134            show_git_diff_gutter: None,
 2135            show_code_actions: None,
 2136            show_runnables: None,
 2137            show_breakpoints: None,
 2138            show_wrap_guides: None,
 2139            show_indent_guides,
 2140            highlight_order: 0,
 2141            highlighted_rows: HashMap::default(),
 2142            background_highlights: HashMap::default(),
 2143            gutter_highlights: HashMap::default(),
 2144            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2145            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2146            nav_history: None,
 2147            context_menu: RefCell::new(None),
 2148            context_menu_options: None,
 2149            mouse_context_menu: None,
 2150            completion_tasks: Vec::new(),
 2151            inline_blame_popover: None,
 2152            inline_blame_popover_show_task: None,
 2153            signature_help_state: SignatureHelpState::default(),
 2154            auto_signature_help: None,
 2155            find_all_references_task_sources: Vec::new(),
 2156            next_completion_id: 0,
 2157            next_inlay_id: 0,
 2158            code_action_providers,
 2159            available_code_actions: None,
 2160            code_actions_task: None,
 2161            quick_selection_highlight_task: None,
 2162            debounced_selection_highlight_task: None,
 2163            document_highlights_task: None,
 2164            linked_editing_range_task: None,
 2165            pending_rename: None,
 2166            searchable: !is_minimap,
 2167            cursor_shape: EditorSettings::get_global(cx)
 2168                .cursor_shape
 2169                .unwrap_or_default(),
 2170            current_line_highlight: None,
 2171            autoindent_mode: Some(AutoindentMode::EachLine),
 2172            collapse_matches: false,
 2173            workspace: None,
 2174            input_enabled: !is_minimap,
 2175            use_modal_editing: full_mode,
 2176            read_only: is_minimap,
 2177            use_autoclose: true,
 2178            use_auto_surround: true,
 2179            auto_replace_emoji_shortcode: false,
 2180            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2181            leader_id: None,
 2182            remote_id: None,
 2183            hover_state: HoverState::default(),
 2184            pending_mouse_down: None,
 2185            hovered_link_state: None,
 2186            edit_prediction_provider: None,
 2187            active_edit_prediction: None,
 2188            stale_edit_prediction_in_menu: None,
 2189            edit_prediction_preview: EditPredictionPreview::Inactive {
 2190                released_too_fast: false,
 2191            },
 2192            inline_diagnostics_enabled: full_mode,
 2193            diagnostics_enabled: full_mode,
 2194            word_completions_enabled: full_mode,
 2195            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2196            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2197            gutter_hovered: false,
 2198            pixel_position_of_newest_cursor: None,
 2199            last_bounds: None,
 2200            last_position_map: None,
 2201            expect_bounds_change: None,
 2202            gutter_dimensions: GutterDimensions::default(),
 2203            style: None,
 2204            show_cursor_names: false,
 2205            hovered_cursors: HashMap::default(),
 2206            next_editor_action_id: EditorActionId::default(),
 2207            editor_actions: Rc::default(),
 2208            edit_predictions_hidden_for_vim_mode: false,
 2209            show_edit_predictions_override: None,
 2210            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2211            edit_prediction_settings: EditPredictionSettings::Disabled,
 2212            edit_prediction_indent_conflict: false,
 2213            edit_prediction_requires_modifier_in_indent_conflict: true,
 2214            custom_context_menu: None,
 2215            show_git_blame_gutter: false,
 2216            show_git_blame_inline: false,
 2217            show_selection_menu: None,
 2218            show_git_blame_inline_delay_task: None,
 2219            git_blame_inline_enabled: full_mode
 2220                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2221            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2222            serialize_dirty_buffers: !is_minimap
 2223                && ProjectSettings::get_global(cx)
 2224                    .session
 2225                    .restore_unsaved_buffers,
 2226            blame: None,
 2227            blame_subscription: None,
 2228            tasks: BTreeMap::default(),
 2229
 2230            breakpoint_store,
 2231            gutter_breakpoint_indicator: (None, None),
 2232            hovered_diff_hunk_row: None,
 2233            _subscriptions: (!is_minimap)
 2234                .then(|| {
 2235                    vec![
 2236                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2237                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2238                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2239                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2240                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2241                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2242                        cx.observe_window_activation(window, |editor, window, cx| {
 2243                            let active = window.is_window_active();
 2244                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2245                                if active {
 2246                                    blink_manager.enable(cx);
 2247                                } else {
 2248                                    blink_manager.disable(cx);
 2249                                }
 2250                            });
 2251                            if active {
 2252                                editor.show_mouse_cursor(cx);
 2253                            }
 2254                        }),
 2255                    ]
 2256                })
 2257                .unwrap_or_default(),
 2258            tasks_update_task: None,
 2259            pull_diagnostics_task: Task::ready(()),
 2260            colors: None,
 2261            refresh_colors_task: Task::ready(()),
 2262            next_color_inlay_id: 0,
 2263            post_scroll_update: Task::ready(()),
 2264            linked_edit_ranges: Default::default(),
 2265            in_project_search: false,
 2266            previous_search_ranges: None,
 2267            breadcrumb_header: None,
 2268            focused_block: None,
 2269            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2270            addons: HashMap::default(),
 2271            registered_buffers: HashMap::default(),
 2272            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2273            selection_mark_mode: false,
 2274            toggle_fold_multiple_buffers: Task::ready(()),
 2275            serialize_selections: Task::ready(()),
 2276            serialize_folds: Task::ready(()),
 2277            text_style_refinement: None,
 2278            load_diff_task: load_uncommitted_diff,
 2279            temporary_diff_override: false,
 2280            mouse_cursor_hidden: false,
 2281            minimap: None,
 2282            hide_mouse_mode: EditorSettings::get_global(cx)
 2283                .hide_mouse
 2284                .unwrap_or_default(),
 2285            change_list: ChangeList::new(),
 2286            mode,
 2287            selection_drag_state: SelectionDragState::None,
 2288            folding_newlines: Task::ready(()),
 2289            lookup_key: None,
 2290        };
 2291
 2292        if is_minimap {
 2293            return editor;
 2294        }
 2295
 2296        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2297            editor
 2298                ._subscriptions
 2299                .push(cx.observe(breakpoints, |_, _, cx| {
 2300                    cx.notify();
 2301                }));
 2302        }
 2303        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2304        editor._subscriptions.extend(project_subscriptions);
 2305
 2306        editor._subscriptions.push(cx.subscribe_in(
 2307            &cx.entity(),
 2308            window,
 2309            |editor, _, e: &EditorEvent, window, cx| match e {
 2310                EditorEvent::ScrollPositionChanged { local, .. } => {
 2311                    if *local {
 2312                        let new_anchor = editor.scroll_manager.anchor();
 2313                        let snapshot = editor.snapshot(window, cx);
 2314                        editor.update_restoration_data(cx, move |data| {
 2315                            data.scroll_position = (
 2316                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2317                                new_anchor.offset,
 2318                            );
 2319                        });
 2320                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2321                        editor.inline_blame_popover.take();
 2322                    }
 2323                }
 2324                EditorEvent::Edited { .. } => {
 2325                    if !vim_enabled(cx) {
 2326                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2327                        let pop_state = editor
 2328                            .change_list
 2329                            .last()
 2330                            .map(|previous| {
 2331                                previous.len() == selections.len()
 2332                                    && previous.iter().enumerate().all(|(ix, p)| {
 2333                                        p.to_display_point(&map).row()
 2334                                            == selections[ix].head().row()
 2335                                    })
 2336                            })
 2337                            .unwrap_or(false);
 2338                        let new_positions = selections
 2339                            .into_iter()
 2340                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2341                            .collect();
 2342                        editor
 2343                            .change_list
 2344                            .push_to_change_list(pop_state, new_positions);
 2345                    }
 2346                }
 2347                _ => (),
 2348            },
 2349        ));
 2350
 2351        if let Some(dap_store) = editor
 2352            .project
 2353            .as_ref()
 2354            .map(|project| project.read(cx).dap_store())
 2355        {
 2356            let weak_editor = cx.weak_entity();
 2357
 2358            editor
 2359                ._subscriptions
 2360                .push(
 2361                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2362                        let session_entity = cx.entity();
 2363                        weak_editor
 2364                            .update(cx, |editor, cx| {
 2365                                editor._subscriptions.push(
 2366                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2367                                );
 2368                            })
 2369                            .ok();
 2370                    }),
 2371                );
 2372
 2373            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2374                editor
 2375                    ._subscriptions
 2376                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2377            }
 2378        }
 2379
 2380        // skip adding the initial selection to selection history
 2381        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2382        editor.end_selection(window, cx);
 2383        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2384
 2385        editor.scroll_manager.show_scrollbars(window, cx);
 2386        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2387
 2388        if full_mode {
 2389            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2390            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2391
 2392            if editor.git_blame_inline_enabled {
 2393                editor.start_git_blame_inline(false, window, cx);
 2394            }
 2395
 2396            editor.go_to_active_debug_line(window, cx);
 2397
 2398            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2399                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2400            }
 2401
 2402            editor.minimap =
 2403                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2404            editor.colors = Some(LspColorData::new(cx));
 2405            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2406        }
 2407
 2408        editor
 2409    }
 2410
 2411    pub fn deploy_mouse_context_menu(
 2412        &mut self,
 2413        position: gpui::Point<Pixels>,
 2414        context_menu: Entity<ContextMenu>,
 2415        window: &mut Window,
 2416        cx: &mut Context<Self>,
 2417    ) {
 2418        self.mouse_context_menu = Some(MouseContextMenu::new(
 2419            self,
 2420            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2421            context_menu,
 2422            window,
 2423            cx,
 2424        ));
 2425    }
 2426
 2427    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2428        self.mouse_context_menu
 2429            .as_ref()
 2430            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2431    }
 2432
 2433    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2434        if self
 2435            .selections
 2436            .pending_anchor()
 2437            .is_some_and(|pending_selection| {
 2438                let snapshot = self.buffer().read(cx).snapshot(cx);
 2439                pending_selection.range().includes(range, &snapshot)
 2440            })
 2441        {
 2442            return true;
 2443        }
 2444
 2445        self.selections
 2446            .disjoint_in_range::<usize>(range.clone(), cx)
 2447            .into_iter()
 2448            .any(|selection| {
 2449                // This is needed to cover a corner case, if we just check for an existing
 2450                // selection in the fold range, having a cursor at the start of the fold
 2451                // marks it as selected. Non-empty selections don't cause this.
 2452                let length = selection.end - selection.start;
 2453                length > 0
 2454            })
 2455    }
 2456
 2457    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2458        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2459    }
 2460
 2461    fn key_context_internal(
 2462        &self,
 2463        has_active_edit_prediction: bool,
 2464        window: &Window,
 2465        cx: &App,
 2466    ) -> KeyContext {
 2467        let mut key_context = KeyContext::new_with_defaults();
 2468        key_context.add("Editor");
 2469        let mode = match self.mode {
 2470            EditorMode::SingleLine => "single_line",
 2471            EditorMode::AutoHeight { .. } => "auto_height",
 2472            EditorMode::Minimap { .. } => "minimap",
 2473            EditorMode::Full { .. } => "full",
 2474        };
 2475
 2476        if EditorSettings::jupyter_enabled(cx) {
 2477            key_context.add("jupyter");
 2478        }
 2479
 2480        key_context.set("mode", mode);
 2481        if self.pending_rename.is_some() {
 2482            key_context.add("renaming");
 2483        }
 2484
 2485        match self.context_menu.borrow().as_ref() {
 2486            Some(CodeContextMenu::Completions(menu)) => {
 2487                if menu.visible() {
 2488                    key_context.add("menu");
 2489                    key_context.add("showing_completions");
 2490                }
 2491            }
 2492            Some(CodeContextMenu::CodeActions(menu)) => {
 2493                if menu.visible() {
 2494                    key_context.add("menu");
 2495                    key_context.add("showing_code_actions")
 2496                }
 2497            }
 2498            None => {}
 2499        }
 2500
 2501        if self.signature_help_state.has_multiple_signatures() {
 2502            key_context.add("showing_signature_help");
 2503        }
 2504
 2505        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2506        if !self.focus_handle(cx).contains_focused(window, cx)
 2507            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2508        {
 2509            for addon in self.addons.values() {
 2510                addon.extend_key_context(&mut key_context, cx)
 2511            }
 2512        }
 2513
 2514        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2515            if let Some(extension) = singleton_buffer
 2516                .read(cx)
 2517                .file()
 2518                .and_then(|file| file.path().extension())
 2519            {
 2520                key_context.set("extension", extension.to_string());
 2521            }
 2522        } else {
 2523            key_context.add("multibuffer");
 2524        }
 2525
 2526        if has_active_edit_prediction {
 2527            if self.edit_prediction_in_conflict() {
 2528                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2529            } else {
 2530                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2531                key_context.add("copilot_suggestion");
 2532            }
 2533        }
 2534
 2535        if self.selection_mark_mode {
 2536            key_context.add("selection_mode");
 2537        }
 2538
 2539        key_context
 2540    }
 2541
 2542    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2543        self.last_bounds.as_ref()
 2544    }
 2545
 2546    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2547        if self.mouse_cursor_hidden {
 2548            self.mouse_cursor_hidden = false;
 2549            cx.notify();
 2550        }
 2551    }
 2552
 2553    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2554        let hide_mouse_cursor = match origin {
 2555            HideMouseCursorOrigin::TypingAction => {
 2556                matches!(
 2557                    self.hide_mouse_mode,
 2558                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2559                )
 2560            }
 2561            HideMouseCursorOrigin::MovementAction => {
 2562                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2563            }
 2564        };
 2565        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2566            self.mouse_cursor_hidden = hide_mouse_cursor;
 2567            cx.notify();
 2568        }
 2569    }
 2570
 2571    pub fn edit_prediction_in_conflict(&self) -> bool {
 2572        if !self.show_edit_predictions_in_menu() {
 2573            return false;
 2574        }
 2575
 2576        let showing_completions = self
 2577            .context_menu
 2578            .borrow()
 2579            .as_ref()
 2580            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2581
 2582        showing_completions
 2583            || self.edit_prediction_requires_modifier()
 2584            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2585            // bindings to insert tab characters.
 2586            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2587    }
 2588
 2589    pub fn accept_edit_prediction_keybind(
 2590        &self,
 2591        accept_partial: bool,
 2592        window: &Window,
 2593        cx: &App,
 2594    ) -> AcceptEditPredictionBinding {
 2595        let key_context = self.key_context_internal(true, window, cx);
 2596        let in_conflict = self.edit_prediction_in_conflict();
 2597
 2598        let bindings = if accept_partial {
 2599            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2600        } else {
 2601            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2602        };
 2603
 2604        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2605        // just the first one.
 2606        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2607            !in_conflict
 2608                || binding
 2609                    .keystrokes()
 2610                    .first()
 2611                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2612        }))
 2613    }
 2614
 2615    pub fn new_file(
 2616        workspace: &mut Workspace,
 2617        _: &workspace::NewFile,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) {
 2621        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2622            "Failed to create buffer",
 2623            window,
 2624            cx,
 2625            |e, _, _| match e.error_code() {
 2626                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2627                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2628                e.error_tag("required").unwrap_or("the latest version")
 2629            )),
 2630                _ => None,
 2631            },
 2632        );
 2633    }
 2634
 2635    pub fn new_in_workspace(
 2636        workspace: &mut Workspace,
 2637        window: &mut Window,
 2638        cx: &mut Context<Workspace>,
 2639    ) -> Task<Result<Entity<Editor>>> {
 2640        let project = workspace.project().clone();
 2641        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2642
 2643        cx.spawn_in(window, async move |workspace, cx| {
 2644            let buffer = create.await?;
 2645            workspace.update_in(cx, |workspace, window, cx| {
 2646                let editor =
 2647                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2648                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2649                editor
 2650            })
 2651        })
 2652    }
 2653
 2654    fn new_file_vertical(
 2655        workspace: &mut Workspace,
 2656        _: &workspace::NewFileSplitVertical,
 2657        window: &mut Window,
 2658        cx: &mut Context<Workspace>,
 2659    ) {
 2660        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2661    }
 2662
 2663    fn new_file_horizontal(
 2664        workspace: &mut Workspace,
 2665        _: &workspace::NewFileSplitHorizontal,
 2666        window: &mut Window,
 2667        cx: &mut Context<Workspace>,
 2668    ) {
 2669        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2670    }
 2671
 2672    fn new_file_in_direction(
 2673        workspace: &mut Workspace,
 2674        direction: SplitDirection,
 2675        window: &mut Window,
 2676        cx: &mut Context<Workspace>,
 2677    ) {
 2678        let project = workspace.project().clone();
 2679        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2680
 2681        cx.spawn_in(window, async move |workspace, cx| {
 2682            let buffer = create.await?;
 2683            workspace.update_in(cx, move |workspace, window, cx| {
 2684                workspace.split_item(
 2685                    direction,
 2686                    Box::new(
 2687                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2688                    ),
 2689                    window,
 2690                    cx,
 2691                )
 2692            })?;
 2693            anyhow::Ok(())
 2694        })
 2695        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2696            match e.error_code() {
 2697                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2698                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2699                e.error_tag("required").unwrap_or("the latest version")
 2700            )),
 2701                _ => None,
 2702            }
 2703        });
 2704    }
 2705
 2706    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2707        self.leader_id
 2708    }
 2709
 2710    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2711        &self.buffer
 2712    }
 2713
 2714    pub fn project(&self) -> Option<&Entity<Project>> {
 2715        self.project.as_ref()
 2716    }
 2717
 2718    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2719        self.workspace.as_ref()?.0.upgrade()
 2720    }
 2721
 2722    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2723        self.buffer().read(cx).title(cx)
 2724    }
 2725
 2726    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2727        let git_blame_gutter_max_author_length = self
 2728            .render_git_blame_gutter(cx)
 2729            .then(|| {
 2730                if let Some(blame) = self.blame.as_ref() {
 2731                    let max_author_length =
 2732                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2733                    Some(max_author_length)
 2734                } else {
 2735                    None
 2736                }
 2737            })
 2738            .flatten();
 2739
 2740        EditorSnapshot {
 2741            mode: self.mode.clone(),
 2742            show_gutter: self.show_gutter,
 2743            show_line_numbers: self.show_line_numbers,
 2744            show_git_diff_gutter: self.show_git_diff_gutter,
 2745            show_code_actions: self.show_code_actions,
 2746            show_runnables: self.show_runnables,
 2747            show_breakpoints: self.show_breakpoints,
 2748            git_blame_gutter_max_author_length,
 2749            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2750            placeholder_display_snapshot: self
 2751                .placeholder_display_map
 2752                .as_ref()
 2753                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2754            scroll_anchor: self.scroll_manager.anchor(),
 2755            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2756            is_focused: self.focus_handle.is_focused(window),
 2757            current_line_highlight: self
 2758                .current_line_highlight
 2759                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2760            gutter_hovered: self.gutter_hovered,
 2761        }
 2762    }
 2763
 2764    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2765        self.buffer.read(cx).language_at(point, cx)
 2766    }
 2767
 2768    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2769        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2770    }
 2771
 2772    pub fn active_excerpt(
 2773        &self,
 2774        cx: &App,
 2775    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2776        self.buffer
 2777            .read(cx)
 2778            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2779    }
 2780
 2781    pub fn mode(&self) -> &EditorMode {
 2782        &self.mode
 2783    }
 2784
 2785    pub fn set_mode(&mut self, mode: EditorMode) {
 2786        self.mode = mode;
 2787    }
 2788
 2789    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2790        self.collaboration_hub.as_deref()
 2791    }
 2792
 2793    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2794        self.collaboration_hub = Some(hub);
 2795    }
 2796
 2797    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2798        self.in_project_search = in_project_search;
 2799    }
 2800
 2801    pub fn set_custom_context_menu(
 2802        &mut self,
 2803        f: impl 'static
 2804        + Fn(
 2805            &mut Self,
 2806            DisplayPoint,
 2807            &mut Window,
 2808            &mut Context<Self>,
 2809        ) -> Option<Entity<ui::ContextMenu>>,
 2810    ) {
 2811        self.custom_context_menu = Some(Box::new(f))
 2812    }
 2813
 2814    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2815        self.completion_provider = provider;
 2816    }
 2817
 2818    #[cfg(any(test, feature = "test-support"))]
 2819    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2820        self.completion_provider.clone()
 2821    }
 2822
 2823    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2824        self.semantics_provider.clone()
 2825    }
 2826
 2827    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2828        self.semantics_provider = provider;
 2829    }
 2830
 2831    pub fn set_edit_prediction_provider<T>(
 2832        &mut self,
 2833        provider: Option<Entity<T>>,
 2834        window: &mut Window,
 2835        cx: &mut Context<Self>,
 2836    ) where
 2837        T: EditPredictionProvider,
 2838    {
 2839        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2840            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2841                if this.focus_handle.is_focused(window) {
 2842                    this.update_visible_edit_prediction(window, cx);
 2843                }
 2844            }),
 2845            provider: Arc::new(provider),
 2846        });
 2847        self.update_edit_prediction_settings(cx);
 2848        self.refresh_edit_prediction(false, false, window, cx);
 2849    }
 2850
 2851    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2852        self.placeholder_display_map
 2853            .as_ref()
 2854            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2855    }
 2856
 2857    pub fn set_placeholder_text(
 2858        &mut self,
 2859        placeholder_text: &str,
 2860        window: &mut Window,
 2861        cx: &mut Context<Self>,
 2862    ) {
 2863        let multibuffer = cx
 2864            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2865
 2866        let style = window.text_style();
 2867
 2868        self.placeholder_display_map = Some(cx.new(|cx| {
 2869            DisplayMap::new(
 2870                multibuffer,
 2871                style.font(),
 2872                style.font_size.to_pixels(window.rem_size()),
 2873                None,
 2874                FILE_HEADER_HEIGHT,
 2875                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2876                Default::default(),
 2877                DiagnosticSeverity::Off,
 2878                cx,
 2879            )
 2880        }));
 2881        cx.notify();
 2882    }
 2883
 2884    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2885        self.cursor_shape = cursor_shape;
 2886
 2887        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2888        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2889
 2890        cx.notify();
 2891    }
 2892
 2893    pub fn set_current_line_highlight(
 2894        &mut self,
 2895        current_line_highlight: Option<CurrentLineHighlight>,
 2896    ) {
 2897        self.current_line_highlight = current_line_highlight;
 2898    }
 2899
 2900    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2901        self.collapse_matches = collapse_matches;
 2902    }
 2903
 2904    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2905        if self.collapse_matches {
 2906            return range.start..range.start;
 2907        }
 2908        range.clone()
 2909    }
 2910
 2911    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2912        if self.display_map.read(cx).clip_at_line_ends != clip {
 2913            self.display_map
 2914                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2915        }
 2916    }
 2917
 2918    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2919        self.input_enabled = input_enabled;
 2920    }
 2921
 2922    pub fn set_edit_predictions_hidden_for_vim_mode(
 2923        &mut self,
 2924        hidden: bool,
 2925        window: &mut Window,
 2926        cx: &mut Context<Self>,
 2927    ) {
 2928        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2929            self.edit_predictions_hidden_for_vim_mode = hidden;
 2930            if hidden {
 2931                self.update_visible_edit_prediction(window, cx);
 2932            } else {
 2933                self.refresh_edit_prediction(true, false, window, cx);
 2934            }
 2935        }
 2936    }
 2937
 2938    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2939        self.menu_edit_predictions_policy = value;
 2940    }
 2941
 2942    pub fn set_autoindent(&mut self, autoindent: bool) {
 2943        if autoindent {
 2944            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2945        } else {
 2946            self.autoindent_mode = None;
 2947        }
 2948    }
 2949
 2950    pub fn read_only(&self, cx: &App) -> bool {
 2951        self.read_only || self.buffer.read(cx).read_only()
 2952    }
 2953
 2954    pub fn set_read_only(&mut self, read_only: bool) {
 2955        self.read_only = read_only;
 2956    }
 2957
 2958    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2959        self.use_autoclose = autoclose;
 2960    }
 2961
 2962    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2963        self.use_auto_surround = auto_surround;
 2964    }
 2965
 2966    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2967        self.auto_replace_emoji_shortcode = auto_replace;
 2968    }
 2969
 2970    pub fn toggle_edit_predictions(
 2971        &mut self,
 2972        _: &ToggleEditPrediction,
 2973        window: &mut Window,
 2974        cx: &mut Context<Self>,
 2975    ) {
 2976        if self.show_edit_predictions_override.is_some() {
 2977            self.set_show_edit_predictions(None, window, cx);
 2978        } else {
 2979            let show_edit_predictions = !self.edit_predictions_enabled();
 2980            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2981        }
 2982    }
 2983
 2984    pub fn set_show_edit_predictions(
 2985        &mut self,
 2986        show_edit_predictions: Option<bool>,
 2987        window: &mut Window,
 2988        cx: &mut Context<Self>,
 2989    ) {
 2990        self.show_edit_predictions_override = show_edit_predictions;
 2991        self.update_edit_prediction_settings(cx);
 2992
 2993        if let Some(false) = show_edit_predictions {
 2994            self.discard_edit_prediction(false, cx);
 2995        } else {
 2996            self.refresh_edit_prediction(false, true, window, cx);
 2997        }
 2998    }
 2999
 3000    fn edit_predictions_disabled_in_scope(
 3001        &self,
 3002        buffer: &Entity<Buffer>,
 3003        buffer_position: language::Anchor,
 3004        cx: &App,
 3005    ) -> bool {
 3006        let snapshot = buffer.read(cx).snapshot();
 3007        let settings = snapshot.settings_at(buffer_position, cx);
 3008
 3009        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3010            return false;
 3011        };
 3012
 3013        scope.override_name().is_some_and(|scope_name| {
 3014            settings
 3015                .edit_predictions_disabled_in
 3016                .iter()
 3017                .any(|s| s == scope_name)
 3018        })
 3019    }
 3020
 3021    pub fn set_use_modal_editing(&mut self, to: bool) {
 3022        self.use_modal_editing = to;
 3023    }
 3024
 3025    pub fn use_modal_editing(&self) -> bool {
 3026        self.use_modal_editing
 3027    }
 3028
 3029    fn selections_did_change(
 3030        &mut self,
 3031        local: bool,
 3032        old_cursor_position: &Anchor,
 3033        effects: SelectionEffects,
 3034        window: &mut Window,
 3035        cx: &mut Context<Self>,
 3036    ) {
 3037        window.invalidate_character_coordinates();
 3038
 3039        // Copy selections to primary selection buffer
 3040        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3041        if local {
 3042            let selections = self.selections.all::<usize>(cx);
 3043            let buffer_handle = self.buffer.read(cx).read(cx);
 3044
 3045            let mut text = String::new();
 3046            for (index, selection) in selections.iter().enumerate() {
 3047                let text_for_selection = buffer_handle
 3048                    .text_for_range(selection.start..selection.end)
 3049                    .collect::<String>();
 3050
 3051                text.push_str(&text_for_selection);
 3052                if index != selections.len() - 1 {
 3053                    text.push('\n');
 3054                }
 3055            }
 3056
 3057            if !text.is_empty() {
 3058                cx.write_to_primary(ClipboardItem::new_string(text));
 3059            }
 3060        }
 3061
 3062        let selection_anchors = self.selections.disjoint_anchors_arc();
 3063
 3064        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3065            self.buffer.update(cx, |buffer, cx| {
 3066                buffer.set_active_selections(
 3067                    &selection_anchors,
 3068                    self.selections.line_mode(),
 3069                    self.cursor_shape,
 3070                    cx,
 3071                )
 3072            });
 3073        }
 3074        let display_map = self
 3075            .display_map
 3076            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3077        let buffer = display_map.buffer_snapshot();
 3078        if self.selections.count() == 1 {
 3079            self.add_selections_state = None;
 3080        }
 3081        self.select_next_state = None;
 3082        self.select_prev_state = None;
 3083        self.select_syntax_node_history.try_clear();
 3084        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3085        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3086        self.take_rename(false, window, cx);
 3087
 3088        let newest_selection = self.selections.newest_anchor();
 3089        let new_cursor_position = newest_selection.head();
 3090        let selection_start = newest_selection.start;
 3091
 3092        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3093            self.push_to_nav_history(
 3094                *old_cursor_position,
 3095                Some(new_cursor_position.to_point(buffer)),
 3096                false,
 3097                effects.nav_history == Some(true),
 3098                cx,
 3099            );
 3100        }
 3101
 3102        if local {
 3103            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3104                self.register_buffer(buffer_id, cx);
 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            refresh_linked_ranges(self, window, cx);
 3155
 3156            self.refresh_selected_text_highlights(false, window, cx);
 3157            refresh_matching_bracket_highlights(self, cx);
 3158            self.update_visible_edit_prediction(window, cx);
 3159            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3160            self.inline_blame_popover.take();
 3161            if self.git_blame_inline_enabled {
 3162                self.start_inline_blame_timer(window, cx);
 3163            }
 3164        }
 3165
 3166        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3167        cx.emit(EditorEvent::SelectionsChanged { local });
 3168
 3169        let selections = &self.selections.disjoint_anchors_arc();
 3170        if selections.len() == 1 {
 3171            cx.emit(SearchEvent::ActiveMatchChanged)
 3172        }
 3173        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3174            let inmemory_selections = selections
 3175                .iter()
 3176                .map(|s| {
 3177                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3178                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3179                })
 3180                .collect();
 3181            self.update_restoration_data(cx, |data| {
 3182                data.selections = inmemory_selections;
 3183            });
 3184
 3185            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3186                && let Some(workspace_id) =
 3187                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3188            {
 3189                let snapshot = self.buffer().read(cx).snapshot(cx);
 3190                let selections = selections.clone();
 3191                let background_executor = cx.background_executor().clone();
 3192                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3193                self.serialize_selections = cx.background_spawn(async move {
 3194                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3195                    let db_selections = selections
 3196                        .iter()
 3197                        .map(|selection| {
 3198                            (
 3199                                selection.start.to_offset(&snapshot),
 3200                                selection.end.to_offset(&snapshot),
 3201                            )
 3202                        })
 3203                        .collect();
 3204
 3205                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3206                        .await
 3207                        .with_context(|| {
 3208                            format!(
 3209                                "persisting editor selections for editor {editor_id}, \
 3210                                workspace {workspace_id:?}"
 3211                            )
 3212                        })
 3213                        .log_err();
 3214                });
 3215            }
 3216        }
 3217
 3218        cx.notify();
 3219    }
 3220
 3221    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3222        use text::ToOffset as _;
 3223        use text::ToPoint as _;
 3224
 3225        if self.mode.is_minimap()
 3226            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3227        {
 3228            return;
 3229        }
 3230
 3231        if !self.buffer().read(cx).is_singleton() {
 3232            return;
 3233        }
 3234
 3235        let display_snapshot = self
 3236            .display_map
 3237            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3238        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3239            return;
 3240        };
 3241        let inmemory_folds = display_snapshot
 3242            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3243            .map(|fold| {
 3244                fold.range.start.text_anchor.to_point(&snapshot)
 3245                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3246            })
 3247            .collect();
 3248        self.update_restoration_data(cx, |data| {
 3249            data.folds = inmemory_folds;
 3250        });
 3251
 3252        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3253            return;
 3254        };
 3255        let background_executor = cx.background_executor().clone();
 3256        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3257        let db_folds = display_snapshot
 3258            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3259            .map(|fold| {
 3260                (
 3261                    fold.range.start.text_anchor.to_offset(&snapshot),
 3262                    fold.range.end.text_anchor.to_offset(&snapshot),
 3263                )
 3264            })
 3265            .collect();
 3266        self.serialize_folds = cx.background_spawn(async move {
 3267            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3268            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3269                .await
 3270                .with_context(|| {
 3271                    format!(
 3272                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3273                    )
 3274                })
 3275                .log_err();
 3276        });
 3277    }
 3278
 3279    pub fn sync_selections(
 3280        &mut self,
 3281        other: Entity<Editor>,
 3282        cx: &mut Context<Self>,
 3283    ) -> gpui::Subscription {
 3284        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3285        if !other_selections.is_empty() {
 3286            self.selections.change_with(cx, |selections| {
 3287                selections.select_anchors(other_selections);
 3288            });
 3289        }
 3290
 3291        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3292            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3293                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3294                if other_selections.is_empty() {
 3295                    return;
 3296                }
 3297                this.selections.change_with(cx, |selections| {
 3298                    selections.select_anchors(other_selections);
 3299                });
 3300            }
 3301        });
 3302
 3303        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3304            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3305                let these_selections = this.selections.disjoint_anchors().to_vec();
 3306                if these_selections.is_empty() {
 3307                    return;
 3308                }
 3309                other.update(cx, |other_editor, cx| {
 3310                    other_editor.selections.change_with(cx, |selections| {
 3311                        selections.select_anchors(these_selections);
 3312                    })
 3313                });
 3314            }
 3315        });
 3316
 3317        Subscription::join(other_subscription, this_subscription)
 3318    }
 3319
 3320    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3321    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3322    /// effects of selection change occur at the end of the transaction.
 3323    pub fn change_selections<R>(
 3324        &mut self,
 3325        effects: SelectionEffects,
 3326        window: &mut Window,
 3327        cx: &mut Context<Self>,
 3328        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3329    ) -> R {
 3330        if let Some(state) = &mut self.deferred_selection_effects_state {
 3331            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3332            state.effects.completions = effects.completions;
 3333            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3334            let (changed, result) = self.selections.change_with(cx, change);
 3335            state.changed |= changed;
 3336            return result;
 3337        }
 3338        let mut state = DeferredSelectionEffectsState {
 3339            changed: false,
 3340            effects,
 3341            old_cursor_position: self.selections.newest_anchor().head(),
 3342            history_entry: SelectionHistoryEntry {
 3343                selections: self.selections.disjoint_anchors_arc(),
 3344                select_next_state: self.select_next_state.clone(),
 3345                select_prev_state: self.select_prev_state.clone(),
 3346                add_selections_state: self.add_selections_state.clone(),
 3347            },
 3348        };
 3349        let (changed, result) = self.selections.change_with(cx, change);
 3350        state.changed = state.changed || changed;
 3351        if self.defer_selection_effects {
 3352            self.deferred_selection_effects_state = Some(state);
 3353        } else {
 3354            self.apply_selection_effects(state, window, cx);
 3355        }
 3356        result
 3357    }
 3358
 3359    /// Defers the effects of selection change, so that the effects of multiple calls to
 3360    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3361    /// to selection history and the state of popovers based on selection position aren't
 3362    /// erroneously updated.
 3363    pub fn with_selection_effects_deferred<R>(
 3364        &mut self,
 3365        window: &mut Window,
 3366        cx: &mut Context<Self>,
 3367        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3368    ) -> R {
 3369        let already_deferred = self.defer_selection_effects;
 3370        self.defer_selection_effects = true;
 3371        let result = update(self, window, cx);
 3372        if !already_deferred {
 3373            self.defer_selection_effects = false;
 3374            if let Some(state) = self.deferred_selection_effects_state.take() {
 3375                self.apply_selection_effects(state, window, cx);
 3376            }
 3377        }
 3378        result
 3379    }
 3380
 3381    fn apply_selection_effects(
 3382        &mut self,
 3383        state: DeferredSelectionEffectsState,
 3384        window: &mut Window,
 3385        cx: &mut Context<Self>,
 3386    ) {
 3387        if state.changed {
 3388            self.selection_history.push(state.history_entry);
 3389
 3390            if let Some(autoscroll) = state.effects.scroll {
 3391                self.request_autoscroll(autoscroll, cx);
 3392            }
 3393
 3394            let old_cursor_position = &state.old_cursor_position;
 3395
 3396            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3397
 3398            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3399                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3400            }
 3401        }
 3402    }
 3403
 3404    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3405    where
 3406        I: IntoIterator<Item = (Range<S>, T)>,
 3407        S: ToOffset,
 3408        T: Into<Arc<str>>,
 3409    {
 3410        if self.read_only(cx) {
 3411            return;
 3412        }
 3413
 3414        self.buffer
 3415            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3416    }
 3417
 3418    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3419    where
 3420        I: IntoIterator<Item = (Range<S>, T)>,
 3421        S: ToOffset,
 3422        T: Into<Arc<str>>,
 3423    {
 3424        if self.read_only(cx) {
 3425            return;
 3426        }
 3427
 3428        self.buffer.update(cx, |buffer, cx| {
 3429            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3430        });
 3431    }
 3432
 3433    pub fn edit_with_block_indent<I, S, T>(
 3434        &mut self,
 3435        edits: I,
 3436        original_indent_columns: Vec<Option<u32>>,
 3437        cx: &mut Context<Self>,
 3438    ) where
 3439        I: IntoIterator<Item = (Range<S>, T)>,
 3440        S: ToOffset,
 3441        T: Into<Arc<str>>,
 3442    {
 3443        if self.read_only(cx) {
 3444            return;
 3445        }
 3446
 3447        self.buffer.update(cx, |buffer, cx| {
 3448            buffer.edit(
 3449                edits,
 3450                Some(AutoindentMode::Block {
 3451                    original_indent_columns,
 3452                }),
 3453                cx,
 3454            )
 3455        });
 3456    }
 3457
 3458    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3459        self.hide_context_menu(window, cx);
 3460
 3461        match phase {
 3462            SelectPhase::Begin {
 3463                position,
 3464                add,
 3465                click_count,
 3466            } => self.begin_selection(position, add, click_count, window, cx),
 3467            SelectPhase::BeginColumnar {
 3468                position,
 3469                goal_column,
 3470                reset,
 3471                mode,
 3472            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3473            SelectPhase::Extend {
 3474                position,
 3475                click_count,
 3476            } => self.extend_selection(position, click_count, window, cx),
 3477            SelectPhase::Update {
 3478                position,
 3479                goal_column,
 3480                scroll_delta,
 3481            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3482            SelectPhase::End => self.end_selection(window, cx),
 3483        }
 3484    }
 3485
 3486    fn extend_selection(
 3487        &mut self,
 3488        position: DisplayPoint,
 3489        click_count: usize,
 3490        window: &mut Window,
 3491        cx: &mut Context<Self>,
 3492    ) {
 3493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3494        let tail = self.selections.newest::<usize>(cx).tail();
 3495        let click_count = click_count.max(match self.selections.select_mode() {
 3496            SelectMode::Character => 1,
 3497            SelectMode::Word(_) => 2,
 3498            SelectMode::Line(_) => 3,
 3499            SelectMode::All => 4,
 3500        });
 3501        self.begin_selection(position, false, click_count, window, cx);
 3502
 3503        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3504
 3505        let current_selection = match self.selections.select_mode() {
 3506            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3507            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3508        };
 3509
 3510        let mut pending_selection = self
 3511            .selections
 3512            .pending_anchor()
 3513            .cloned()
 3514            .expect("extend_selection not called with pending selection");
 3515
 3516        if pending_selection
 3517            .start
 3518            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3519            == Ordering::Greater
 3520        {
 3521            pending_selection.start = current_selection.start;
 3522        }
 3523        if pending_selection
 3524            .end
 3525            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3526            == Ordering::Less
 3527        {
 3528            pending_selection.end = current_selection.end;
 3529            pending_selection.reversed = true;
 3530        }
 3531
 3532        let mut pending_mode = self.selections.pending_mode().unwrap();
 3533        match &mut pending_mode {
 3534            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3535            _ => {}
 3536        }
 3537
 3538        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3539            SelectionEffects::scroll(Autoscroll::fit())
 3540        } else {
 3541            SelectionEffects::no_scroll()
 3542        };
 3543
 3544        self.change_selections(effects, window, cx, |s| {
 3545            s.set_pending(pending_selection.clone(), pending_mode);
 3546            s.set_is_extending(true);
 3547        });
 3548    }
 3549
 3550    fn begin_selection(
 3551        &mut self,
 3552        position: DisplayPoint,
 3553        add: bool,
 3554        click_count: usize,
 3555        window: &mut Window,
 3556        cx: &mut Context<Self>,
 3557    ) {
 3558        if !self.focus_handle.is_focused(window) {
 3559            self.last_focused_descendant = None;
 3560            window.focus(&self.focus_handle);
 3561        }
 3562
 3563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3564        let buffer = display_map.buffer_snapshot();
 3565        let position = display_map.clip_point(position, Bias::Left);
 3566
 3567        let start;
 3568        let end;
 3569        let mode;
 3570        let mut auto_scroll;
 3571        match click_count {
 3572            1 => {
 3573                start = buffer.anchor_before(position.to_point(&display_map));
 3574                end = start;
 3575                mode = SelectMode::Character;
 3576                auto_scroll = true;
 3577            }
 3578            2 => {
 3579                let position = display_map
 3580                    .clip_point(position, Bias::Left)
 3581                    .to_offset(&display_map, Bias::Left);
 3582                let (range, _) = buffer.surrounding_word(position, None);
 3583                start = buffer.anchor_before(range.start);
 3584                end = buffer.anchor_before(range.end);
 3585                mode = SelectMode::Word(start..end);
 3586                auto_scroll = true;
 3587            }
 3588            3 => {
 3589                let position = display_map
 3590                    .clip_point(position, Bias::Left)
 3591                    .to_point(&display_map);
 3592                let line_start = display_map.prev_line_boundary(position).0;
 3593                let next_line_start = buffer.clip_point(
 3594                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3595                    Bias::Left,
 3596                );
 3597                start = buffer.anchor_before(line_start);
 3598                end = buffer.anchor_before(next_line_start);
 3599                mode = SelectMode::Line(start..end);
 3600                auto_scroll = true;
 3601            }
 3602            _ => {
 3603                start = buffer.anchor_before(0);
 3604                end = buffer.anchor_before(buffer.len());
 3605                mode = SelectMode::All;
 3606                auto_scroll = false;
 3607            }
 3608        }
 3609        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3610
 3611        let point_to_delete: Option<usize> = {
 3612            let selected_points: Vec<Selection<Point>> =
 3613                self.selections.disjoint_in_range(start..end, cx);
 3614
 3615            if !add || click_count > 1 {
 3616                None
 3617            } else if !selected_points.is_empty() {
 3618                Some(selected_points[0].id)
 3619            } else {
 3620                let clicked_point_already_selected =
 3621                    self.selections.disjoint_anchors().iter().find(|selection| {
 3622                        selection.start.to_point(buffer) == start.to_point(buffer)
 3623                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3624                    });
 3625
 3626                clicked_point_already_selected.map(|selection| selection.id)
 3627            }
 3628        };
 3629
 3630        let selections_count = self.selections.count();
 3631        let effects = if auto_scroll {
 3632            SelectionEffects::default()
 3633        } else {
 3634            SelectionEffects::no_scroll()
 3635        };
 3636
 3637        self.change_selections(effects, window, cx, |s| {
 3638            if let Some(point_to_delete) = point_to_delete {
 3639                s.delete(point_to_delete);
 3640
 3641                if selections_count == 1 {
 3642                    s.set_pending_anchor_range(start..end, mode);
 3643                }
 3644            } else {
 3645                if !add {
 3646                    s.clear_disjoint();
 3647                }
 3648
 3649                s.set_pending_anchor_range(start..end, mode);
 3650            }
 3651        });
 3652    }
 3653
 3654    fn begin_columnar_selection(
 3655        &mut self,
 3656        position: DisplayPoint,
 3657        goal_column: u32,
 3658        reset: bool,
 3659        mode: ColumnarMode,
 3660        window: &mut Window,
 3661        cx: &mut Context<Self>,
 3662    ) {
 3663        if !self.focus_handle.is_focused(window) {
 3664            self.last_focused_descendant = None;
 3665            window.focus(&self.focus_handle);
 3666        }
 3667
 3668        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3669
 3670        if reset {
 3671            let pointer_position = display_map
 3672                .buffer_snapshot()
 3673                .anchor_before(position.to_point(&display_map));
 3674
 3675            self.change_selections(
 3676                SelectionEffects::scroll(Autoscroll::newest()),
 3677                window,
 3678                cx,
 3679                |s| {
 3680                    s.clear_disjoint();
 3681                    s.set_pending_anchor_range(
 3682                        pointer_position..pointer_position,
 3683                        SelectMode::Character,
 3684                    );
 3685                },
 3686            );
 3687        };
 3688
 3689        let tail = self.selections.newest::<Point>(cx).tail();
 3690        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3691        self.columnar_selection_state = match mode {
 3692            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3693                selection_tail: selection_anchor,
 3694                display_point: if reset {
 3695                    if position.column() != goal_column {
 3696                        Some(DisplayPoint::new(position.row(), goal_column))
 3697                    } else {
 3698                        None
 3699                    }
 3700                } else {
 3701                    None
 3702                },
 3703            }),
 3704            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3705                selection_tail: selection_anchor,
 3706            }),
 3707        };
 3708
 3709        if !reset {
 3710            self.select_columns(position, goal_column, &display_map, window, cx);
 3711        }
 3712    }
 3713
 3714    fn update_selection(
 3715        &mut self,
 3716        position: DisplayPoint,
 3717        goal_column: u32,
 3718        scroll_delta: gpui::Point<f32>,
 3719        window: &mut Window,
 3720        cx: &mut Context<Self>,
 3721    ) {
 3722        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3723
 3724        if self.columnar_selection_state.is_some() {
 3725            self.select_columns(position, goal_column, &display_map, window, cx);
 3726        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3727            let buffer = display_map.buffer_snapshot();
 3728            let head;
 3729            let tail;
 3730            let mode = self.selections.pending_mode().unwrap();
 3731            match &mode {
 3732                SelectMode::Character => {
 3733                    head = position.to_point(&display_map);
 3734                    tail = pending.tail().to_point(buffer);
 3735                }
 3736                SelectMode::Word(original_range) => {
 3737                    let offset = display_map
 3738                        .clip_point(position, Bias::Left)
 3739                        .to_offset(&display_map, Bias::Left);
 3740                    let original_range = original_range.to_offset(buffer);
 3741
 3742                    let head_offset = if buffer.is_inside_word(offset, None)
 3743                        || original_range.contains(&offset)
 3744                    {
 3745                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3746                        if word_range.start < original_range.start {
 3747                            word_range.start
 3748                        } else {
 3749                            word_range.end
 3750                        }
 3751                    } else {
 3752                        offset
 3753                    };
 3754
 3755                    head = head_offset.to_point(buffer);
 3756                    if head_offset <= original_range.start {
 3757                        tail = original_range.end.to_point(buffer);
 3758                    } else {
 3759                        tail = original_range.start.to_point(buffer);
 3760                    }
 3761                }
 3762                SelectMode::Line(original_range) => {
 3763                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3764
 3765                    let position = display_map
 3766                        .clip_point(position, Bias::Left)
 3767                        .to_point(&display_map);
 3768                    let line_start = display_map.prev_line_boundary(position).0;
 3769                    let next_line_start = buffer.clip_point(
 3770                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3771                        Bias::Left,
 3772                    );
 3773
 3774                    if line_start < original_range.start {
 3775                        head = line_start
 3776                    } else {
 3777                        head = next_line_start
 3778                    }
 3779
 3780                    if head <= original_range.start {
 3781                        tail = original_range.end;
 3782                    } else {
 3783                        tail = original_range.start;
 3784                    }
 3785                }
 3786                SelectMode::All => {
 3787                    return;
 3788                }
 3789            };
 3790
 3791            if head < tail {
 3792                pending.start = buffer.anchor_before(head);
 3793                pending.end = buffer.anchor_before(tail);
 3794                pending.reversed = true;
 3795            } else {
 3796                pending.start = buffer.anchor_before(tail);
 3797                pending.end = buffer.anchor_before(head);
 3798                pending.reversed = false;
 3799            }
 3800
 3801            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3802                s.set_pending(pending.clone(), mode);
 3803            });
 3804        } else {
 3805            log::error!("update_selection dispatched with no pending selection");
 3806            return;
 3807        }
 3808
 3809        self.apply_scroll_delta(scroll_delta, window, cx);
 3810        cx.notify();
 3811    }
 3812
 3813    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3814        self.columnar_selection_state.take();
 3815        if let Some(pending_mode) = self.selections.pending_mode() {
 3816            let selections = self.selections.all::<usize>(cx);
 3817            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3818                s.select(selections);
 3819                s.clear_pending();
 3820                if s.is_extending() {
 3821                    s.set_is_extending(false);
 3822                } else {
 3823                    s.set_select_mode(pending_mode);
 3824                }
 3825            });
 3826        }
 3827    }
 3828
 3829    fn select_columns(
 3830        &mut self,
 3831        head: DisplayPoint,
 3832        goal_column: u32,
 3833        display_map: &DisplaySnapshot,
 3834        window: &mut Window,
 3835        cx: &mut Context<Self>,
 3836    ) {
 3837        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3838            return;
 3839        };
 3840
 3841        let tail = match columnar_state {
 3842            ColumnarSelectionState::FromMouse {
 3843                selection_tail,
 3844                display_point,
 3845            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3846            ColumnarSelectionState::FromSelection { selection_tail } => {
 3847                selection_tail.to_display_point(display_map)
 3848            }
 3849        };
 3850
 3851        let start_row = cmp::min(tail.row(), head.row());
 3852        let end_row = cmp::max(tail.row(), head.row());
 3853        let start_column = cmp::min(tail.column(), goal_column);
 3854        let end_column = cmp::max(tail.column(), goal_column);
 3855        let reversed = start_column < tail.column();
 3856
 3857        let selection_ranges = (start_row.0..=end_row.0)
 3858            .map(DisplayRow)
 3859            .filter_map(|row| {
 3860                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3861                    || start_column <= display_map.line_len(row))
 3862                    && !display_map.is_block_line(row)
 3863                {
 3864                    let start = display_map
 3865                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3866                        .to_point(display_map);
 3867                    let end = display_map
 3868                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3869                        .to_point(display_map);
 3870                    if reversed {
 3871                        Some(end..start)
 3872                    } else {
 3873                        Some(start..end)
 3874                    }
 3875                } else {
 3876                    None
 3877                }
 3878            })
 3879            .collect::<Vec<_>>();
 3880        if selection_ranges.is_empty() {
 3881            return;
 3882        }
 3883
 3884        let ranges = match columnar_state {
 3885            ColumnarSelectionState::FromMouse { .. } => {
 3886                let mut non_empty_ranges = selection_ranges
 3887                    .iter()
 3888                    .filter(|selection_range| selection_range.start != selection_range.end)
 3889                    .peekable();
 3890                if non_empty_ranges.peek().is_some() {
 3891                    non_empty_ranges.cloned().collect()
 3892                } else {
 3893                    selection_ranges
 3894                }
 3895            }
 3896            _ => selection_ranges,
 3897        };
 3898
 3899        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3900            s.select_ranges(ranges);
 3901        });
 3902        cx.notify();
 3903    }
 3904
 3905    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3906        self.selections
 3907            .all_adjusted(cx)
 3908            .iter()
 3909            .any(|selection| !selection.is_empty())
 3910    }
 3911
 3912    pub fn has_pending_nonempty_selection(&self) -> bool {
 3913        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3914            Some(Selection { start, end, .. }) => start != end,
 3915            None => false,
 3916        };
 3917
 3918        pending_nonempty_selection
 3919            || (self.columnar_selection_state.is_some()
 3920                && self.selections.disjoint_anchors().len() > 1)
 3921    }
 3922
 3923    pub fn has_pending_selection(&self) -> bool {
 3924        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3925    }
 3926
 3927    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3928        self.selection_mark_mode = false;
 3929        self.selection_drag_state = SelectionDragState::None;
 3930
 3931        if self.clear_expanded_diff_hunks(cx) {
 3932            cx.notify();
 3933            return;
 3934        }
 3935        if self.dismiss_menus_and_popups(true, window, cx) {
 3936            return;
 3937        }
 3938
 3939        if self.mode.is_full()
 3940            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3941        {
 3942            return;
 3943        }
 3944
 3945        cx.propagate();
 3946    }
 3947
 3948    pub fn dismiss_menus_and_popups(
 3949        &mut self,
 3950        is_user_requested: bool,
 3951        window: &mut Window,
 3952        cx: &mut Context<Self>,
 3953    ) -> bool {
 3954        if self.take_rename(false, window, cx).is_some() {
 3955            return true;
 3956        }
 3957
 3958        if hide_hover(self, cx) {
 3959            return true;
 3960        }
 3961
 3962        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3963            return true;
 3964        }
 3965
 3966        if self.hide_context_menu(window, cx).is_some() {
 3967            return true;
 3968        }
 3969
 3970        if self.mouse_context_menu.take().is_some() {
 3971            return true;
 3972        }
 3973
 3974        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3975            return true;
 3976        }
 3977
 3978        if self.snippet_stack.pop().is_some() {
 3979            return true;
 3980        }
 3981
 3982        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3983            self.dismiss_diagnostics(cx);
 3984            return true;
 3985        }
 3986
 3987        false
 3988    }
 3989
 3990    fn linked_editing_ranges_for(
 3991        &self,
 3992        selection: Range<text::Anchor>,
 3993        cx: &App,
 3994    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3995        if self.linked_edit_ranges.is_empty() {
 3996            return None;
 3997        }
 3998        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3999            selection.end.buffer_id.and_then(|end_buffer_id| {
 4000                if selection.start.buffer_id != Some(end_buffer_id) {
 4001                    return None;
 4002                }
 4003                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4004                let snapshot = buffer.read(cx).snapshot();
 4005                self.linked_edit_ranges
 4006                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4007                    .map(|ranges| (ranges, snapshot, buffer))
 4008            })?;
 4009        use text::ToOffset as TO;
 4010        // find offset from the start of current range to current cursor position
 4011        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4012
 4013        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4014        let start_difference = start_offset - start_byte_offset;
 4015        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4016        let end_difference = end_offset - start_byte_offset;
 4017        // Current range has associated linked ranges.
 4018        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4019        for range in linked_ranges.iter() {
 4020            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4021            let end_offset = start_offset + end_difference;
 4022            let start_offset = start_offset + start_difference;
 4023            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4024                continue;
 4025            }
 4026            if self.selections.disjoint_anchor_ranges().any(|s| {
 4027                if s.start.buffer_id != selection.start.buffer_id
 4028                    || s.end.buffer_id != selection.end.buffer_id
 4029                {
 4030                    return false;
 4031                }
 4032                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4033                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4034            }) {
 4035                continue;
 4036            }
 4037            let start = buffer_snapshot.anchor_after(start_offset);
 4038            let end = buffer_snapshot.anchor_after(end_offset);
 4039            linked_edits
 4040                .entry(buffer.clone())
 4041                .or_default()
 4042                .push(start..end);
 4043        }
 4044        Some(linked_edits)
 4045    }
 4046
 4047    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4048        let text: Arc<str> = text.into();
 4049
 4050        if self.read_only(cx) {
 4051            return;
 4052        }
 4053
 4054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4055
 4056        let selections = self.selections.all_adjusted(cx);
 4057        let mut bracket_inserted = false;
 4058        let mut edits = Vec::new();
 4059        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4060        let mut new_selections = Vec::with_capacity(selections.len());
 4061        let mut new_autoclose_regions = Vec::new();
 4062        let snapshot = self.buffer.read(cx).read(cx);
 4063        let mut clear_linked_edit_ranges = false;
 4064
 4065        for (selection, autoclose_region) in
 4066            self.selections_with_autoclose_regions(selections, &snapshot)
 4067        {
 4068            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4069                // Determine if the inserted text matches the opening or closing
 4070                // bracket of any of this language's bracket pairs.
 4071                let mut bracket_pair = None;
 4072                let mut is_bracket_pair_start = false;
 4073                let mut is_bracket_pair_end = false;
 4074                if !text.is_empty() {
 4075                    let mut bracket_pair_matching_end = None;
 4076                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4077                    //  and they are removing the character that triggered IME popup.
 4078                    for (pair, enabled) in scope.brackets() {
 4079                        if !pair.close && !pair.surround {
 4080                            continue;
 4081                        }
 4082
 4083                        if enabled && pair.start.ends_with(text.as_ref()) {
 4084                            let prefix_len = pair.start.len() - text.len();
 4085                            let preceding_text_matches_prefix = prefix_len == 0
 4086                                || (selection.start.column >= (prefix_len as u32)
 4087                                    && snapshot.contains_str_at(
 4088                                        Point::new(
 4089                                            selection.start.row,
 4090                                            selection.start.column - (prefix_len as u32),
 4091                                        ),
 4092                                        &pair.start[..prefix_len],
 4093                                    ));
 4094                            if preceding_text_matches_prefix {
 4095                                bracket_pair = Some(pair.clone());
 4096                                is_bracket_pair_start = true;
 4097                                break;
 4098                            }
 4099                        }
 4100                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4101                        {
 4102                            // take first bracket pair matching end, but don't break in case a later bracket
 4103                            // pair matches start
 4104                            bracket_pair_matching_end = Some(pair.clone());
 4105                        }
 4106                    }
 4107                    if let Some(end) = bracket_pair_matching_end
 4108                        && bracket_pair.is_none()
 4109                    {
 4110                        bracket_pair = Some(end);
 4111                        is_bracket_pair_end = true;
 4112                    }
 4113                }
 4114
 4115                if let Some(bracket_pair) = bracket_pair {
 4116                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4117                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4118                    let auto_surround =
 4119                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4120                    if selection.is_empty() {
 4121                        if is_bracket_pair_start {
 4122                            // If the inserted text is a suffix of an opening bracket and the
 4123                            // selection is preceded by the rest of the opening bracket, then
 4124                            // insert the closing bracket.
 4125                            let following_text_allows_autoclose = snapshot
 4126                                .chars_at(selection.start)
 4127                                .next()
 4128                                .is_none_or(|c| scope.should_autoclose_before(c));
 4129
 4130                            let preceding_text_allows_autoclose = selection.start.column == 0
 4131                                || snapshot
 4132                                    .reversed_chars_at(selection.start)
 4133                                    .next()
 4134                                    .is_none_or(|c| {
 4135                                        bracket_pair.start != bracket_pair.end
 4136                                            || !snapshot
 4137                                                .char_classifier_at(selection.start)
 4138                                                .is_word(c)
 4139                                    });
 4140
 4141                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4142                                && bracket_pair.start.len() == 1
 4143                            {
 4144                                let target = bracket_pair.start.chars().next().unwrap();
 4145                                let current_line_count = snapshot
 4146                                    .reversed_chars_at(selection.start)
 4147                                    .take_while(|&c| c != '\n')
 4148                                    .filter(|&c| c == target)
 4149                                    .count();
 4150                                current_line_count % 2 == 1
 4151                            } else {
 4152                                false
 4153                            };
 4154
 4155                            if autoclose
 4156                                && bracket_pair.close
 4157                                && following_text_allows_autoclose
 4158                                && preceding_text_allows_autoclose
 4159                                && !is_closing_quote
 4160                            {
 4161                                let anchor = snapshot.anchor_before(selection.end);
 4162                                new_selections.push((selection.map(|_| anchor), text.len()));
 4163                                new_autoclose_regions.push((
 4164                                    anchor,
 4165                                    text.len(),
 4166                                    selection.id,
 4167                                    bracket_pair.clone(),
 4168                                ));
 4169                                edits.push((
 4170                                    selection.range(),
 4171                                    format!("{}{}", text, bracket_pair.end).into(),
 4172                                ));
 4173                                bracket_inserted = true;
 4174                                continue;
 4175                            }
 4176                        }
 4177
 4178                        if let Some(region) = autoclose_region {
 4179                            // If the selection is followed by an auto-inserted closing bracket,
 4180                            // then don't insert that closing bracket again; just move the selection
 4181                            // past the closing bracket.
 4182                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4183                                && text.as_ref() == region.pair.end.as_str()
 4184                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4185                            if should_skip {
 4186                                let anchor = snapshot.anchor_after(selection.end);
 4187                                new_selections
 4188                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4189                                continue;
 4190                            }
 4191                        }
 4192
 4193                        let always_treat_brackets_as_autoclosed = snapshot
 4194                            .language_settings_at(selection.start, cx)
 4195                            .always_treat_brackets_as_autoclosed;
 4196                        if always_treat_brackets_as_autoclosed
 4197                            && is_bracket_pair_end
 4198                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4199                        {
 4200                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4201                            // and the inserted text is a closing bracket and the selection is followed
 4202                            // by the closing bracket then move the selection past the closing bracket.
 4203                            let anchor = snapshot.anchor_after(selection.end);
 4204                            new_selections.push((selection.map(|_| anchor), text.len()));
 4205                            continue;
 4206                        }
 4207                    }
 4208                    // If an opening bracket is 1 character long and is typed while
 4209                    // text is selected, then surround that text with the bracket pair.
 4210                    else if auto_surround
 4211                        && bracket_pair.surround
 4212                        && is_bracket_pair_start
 4213                        && bracket_pair.start.chars().count() == 1
 4214                    {
 4215                        edits.push((selection.start..selection.start, text.clone()));
 4216                        edits.push((
 4217                            selection.end..selection.end,
 4218                            bracket_pair.end.as_str().into(),
 4219                        ));
 4220                        bracket_inserted = true;
 4221                        new_selections.push((
 4222                            Selection {
 4223                                id: selection.id,
 4224                                start: snapshot.anchor_after(selection.start),
 4225                                end: snapshot.anchor_before(selection.end),
 4226                                reversed: selection.reversed,
 4227                                goal: selection.goal,
 4228                            },
 4229                            0,
 4230                        ));
 4231                        continue;
 4232                    }
 4233                }
 4234            }
 4235
 4236            if self.auto_replace_emoji_shortcode
 4237                && selection.is_empty()
 4238                && text.as_ref().ends_with(':')
 4239                && let Some(possible_emoji_short_code) =
 4240                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4241                && !possible_emoji_short_code.is_empty()
 4242                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4243            {
 4244                let emoji_shortcode_start = Point::new(
 4245                    selection.start.row,
 4246                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4247                );
 4248
 4249                // Remove shortcode from buffer
 4250                edits.push((
 4251                    emoji_shortcode_start..selection.start,
 4252                    "".to_string().into(),
 4253                ));
 4254                new_selections.push((
 4255                    Selection {
 4256                        id: selection.id,
 4257                        start: snapshot.anchor_after(emoji_shortcode_start),
 4258                        end: snapshot.anchor_before(selection.start),
 4259                        reversed: selection.reversed,
 4260                        goal: selection.goal,
 4261                    },
 4262                    0,
 4263                ));
 4264
 4265                // Insert emoji
 4266                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4267                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4268                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4269
 4270                continue;
 4271            }
 4272
 4273            // If not handling any auto-close operation, then just replace the selected
 4274            // text with the given input and move the selection to the end of the
 4275            // newly inserted text.
 4276            let anchor = snapshot.anchor_after(selection.end);
 4277            if !self.linked_edit_ranges.is_empty() {
 4278                let start_anchor = snapshot.anchor_before(selection.start);
 4279
 4280                let is_word_char = text.chars().next().is_none_or(|char| {
 4281                    let classifier = snapshot
 4282                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4283                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4284                    classifier.is_word(char)
 4285                });
 4286
 4287                if is_word_char {
 4288                    if let Some(ranges) = self
 4289                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4290                    {
 4291                        for (buffer, edits) in ranges {
 4292                            linked_edits
 4293                                .entry(buffer.clone())
 4294                                .or_default()
 4295                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4296                        }
 4297                    }
 4298                } else {
 4299                    clear_linked_edit_ranges = true;
 4300                }
 4301            }
 4302
 4303            new_selections.push((selection.map(|_| anchor), 0));
 4304            edits.push((selection.start..selection.end, text.clone()));
 4305        }
 4306
 4307        drop(snapshot);
 4308
 4309        self.transact(window, cx, |this, window, cx| {
 4310            if clear_linked_edit_ranges {
 4311                this.linked_edit_ranges.clear();
 4312            }
 4313            let initial_buffer_versions =
 4314                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4315
 4316            this.buffer.update(cx, |buffer, cx| {
 4317                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4318            });
 4319            for (buffer, edits) in linked_edits {
 4320                buffer.update(cx, |buffer, cx| {
 4321                    let snapshot = buffer.snapshot();
 4322                    let edits = edits
 4323                        .into_iter()
 4324                        .map(|(range, text)| {
 4325                            use text::ToPoint as TP;
 4326                            let end_point = TP::to_point(&range.end, &snapshot);
 4327                            let start_point = TP::to_point(&range.start, &snapshot);
 4328                            (start_point..end_point, text)
 4329                        })
 4330                        .sorted_by_key(|(range, _)| range.start);
 4331                    buffer.edit(edits, None, cx);
 4332                })
 4333            }
 4334            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4335            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4336            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4337            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4338                .zip(new_selection_deltas)
 4339                .map(|(selection, delta)| Selection {
 4340                    id: selection.id,
 4341                    start: selection.start + delta,
 4342                    end: selection.end + delta,
 4343                    reversed: selection.reversed,
 4344                    goal: SelectionGoal::None,
 4345                })
 4346                .collect::<Vec<_>>();
 4347
 4348            let mut i = 0;
 4349            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4350                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4351                let start = map.buffer_snapshot().anchor_before(position);
 4352                let end = map.buffer_snapshot().anchor_after(position);
 4353                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4354                    match existing_state
 4355                        .range
 4356                        .start
 4357                        .cmp(&start, map.buffer_snapshot())
 4358                    {
 4359                        Ordering::Less => i += 1,
 4360                        Ordering::Greater => break,
 4361                        Ordering::Equal => {
 4362                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4363                                Ordering::Less => i += 1,
 4364                                Ordering::Equal => break,
 4365                                Ordering::Greater => break,
 4366                            }
 4367                        }
 4368                    }
 4369                }
 4370                this.autoclose_regions.insert(
 4371                    i,
 4372                    AutocloseRegion {
 4373                        selection_id,
 4374                        range: start..end,
 4375                        pair,
 4376                    },
 4377                );
 4378            }
 4379
 4380            let had_active_edit_prediction = this.has_active_edit_prediction();
 4381            this.change_selections(
 4382                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4383                window,
 4384                cx,
 4385                |s| s.select(new_selections),
 4386            );
 4387
 4388            if !bracket_inserted
 4389                && let Some(on_type_format_task) =
 4390                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4391            {
 4392                on_type_format_task.detach_and_log_err(cx);
 4393            }
 4394
 4395            let editor_settings = EditorSettings::get_global(cx);
 4396            if bracket_inserted
 4397                && (editor_settings.auto_signature_help
 4398                    || editor_settings.show_signature_help_after_edits)
 4399            {
 4400                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4401            }
 4402
 4403            let trigger_in_words =
 4404                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4405            if this.hard_wrap.is_some() {
 4406                let latest: Range<Point> = this.selections.newest(cx).range();
 4407                if latest.is_empty()
 4408                    && this
 4409                        .buffer()
 4410                        .read(cx)
 4411                        .snapshot(cx)
 4412                        .line_len(MultiBufferRow(latest.start.row))
 4413                        == latest.start.column
 4414                {
 4415                    this.rewrap_impl(
 4416                        RewrapOptions {
 4417                            override_language_settings: true,
 4418                            preserve_existing_whitespace: true,
 4419                        },
 4420                        cx,
 4421                    )
 4422                }
 4423            }
 4424            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4425            refresh_linked_ranges(this, window, cx);
 4426            this.refresh_edit_prediction(true, false, window, cx);
 4427            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4428        });
 4429    }
 4430
 4431    fn find_possible_emoji_shortcode_at_position(
 4432        snapshot: &MultiBufferSnapshot,
 4433        position: Point,
 4434    ) -> Option<String> {
 4435        let mut chars = Vec::new();
 4436        let mut found_colon = false;
 4437        for char in snapshot.reversed_chars_at(position).take(100) {
 4438            // Found a possible emoji shortcode in the middle of the buffer
 4439            if found_colon {
 4440                if char.is_whitespace() {
 4441                    chars.reverse();
 4442                    return Some(chars.iter().collect());
 4443                }
 4444                // If the previous character is not a whitespace, we are in the middle of a word
 4445                // and we only want to complete the shortcode if the word is made up of other emojis
 4446                let mut containing_word = String::new();
 4447                for ch in snapshot
 4448                    .reversed_chars_at(position)
 4449                    .skip(chars.len() + 1)
 4450                    .take(100)
 4451                {
 4452                    if ch.is_whitespace() {
 4453                        break;
 4454                    }
 4455                    containing_word.push(ch);
 4456                }
 4457                let containing_word = containing_word.chars().rev().collect::<String>();
 4458                if util::word_consists_of_emojis(containing_word.as_str()) {
 4459                    chars.reverse();
 4460                    return Some(chars.iter().collect());
 4461                }
 4462            }
 4463
 4464            if char.is_whitespace() || !char.is_ascii() {
 4465                return None;
 4466            }
 4467            if char == ':' {
 4468                found_colon = true;
 4469            } else {
 4470                chars.push(char);
 4471            }
 4472        }
 4473        // Found a possible emoji shortcode at the beginning of the buffer
 4474        chars.reverse();
 4475        Some(chars.iter().collect())
 4476    }
 4477
 4478    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4480        self.transact(window, cx, |this, window, cx| {
 4481            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4482                let selections = this.selections.all::<usize>(cx);
 4483                let multi_buffer = this.buffer.read(cx);
 4484                let buffer = multi_buffer.snapshot(cx);
 4485                selections
 4486                    .iter()
 4487                    .map(|selection| {
 4488                        let start_point = selection.start.to_point(&buffer);
 4489                        let mut existing_indent =
 4490                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4491                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4492                        let start = selection.start;
 4493                        let end = selection.end;
 4494                        let selection_is_empty = start == end;
 4495                        let language_scope = buffer.language_scope_at(start);
 4496                        let (
 4497                            comment_delimiter,
 4498                            doc_delimiter,
 4499                            insert_extra_newline,
 4500                            indent_on_newline,
 4501                            indent_on_extra_newline,
 4502                        ) = if let Some(language) = &language_scope {
 4503                            let mut insert_extra_newline =
 4504                                insert_extra_newline_brackets(&buffer, start..end, language)
 4505                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4506
 4507                            // Comment extension on newline is allowed only for cursor selections
 4508                            let comment_delimiter = maybe!({
 4509                                if !selection_is_empty {
 4510                                    return None;
 4511                                }
 4512
 4513                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4514                                    return None;
 4515                                }
 4516
 4517                                let delimiters = language.line_comment_prefixes();
 4518                                let max_len_of_delimiter =
 4519                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4520                                let (snapshot, range) =
 4521                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4522
 4523                                let num_of_whitespaces = snapshot
 4524                                    .chars_for_range(range.clone())
 4525                                    .take_while(|c| c.is_whitespace())
 4526                                    .count();
 4527                                let comment_candidate = snapshot
 4528                                    .chars_for_range(range.clone())
 4529                                    .skip(num_of_whitespaces)
 4530                                    .take(max_len_of_delimiter)
 4531                                    .collect::<String>();
 4532                                let (delimiter, trimmed_len) = delimiters
 4533                                    .iter()
 4534                                    .filter_map(|delimiter| {
 4535                                        let prefix = delimiter.trim_end();
 4536                                        if comment_candidate.starts_with(prefix) {
 4537                                            Some((delimiter, prefix.len()))
 4538                                        } else {
 4539                                            None
 4540                                        }
 4541                                    })
 4542                                    .max_by_key(|(_, len)| *len)?;
 4543
 4544                                if let Some(BlockCommentConfig {
 4545                                    start: block_start, ..
 4546                                }) = language.block_comment()
 4547                                {
 4548                                    let block_start_trimmed = block_start.trim_end();
 4549                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4550                                        let line_content = snapshot
 4551                                            .chars_for_range(range)
 4552                                            .skip(num_of_whitespaces)
 4553                                            .take(block_start_trimmed.len())
 4554                                            .collect::<String>();
 4555
 4556                                        if line_content.starts_with(block_start_trimmed) {
 4557                                            return None;
 4558                                        }
 4559                                    }
 4560                                }
 4561
 4562                                let cursor_is_placed_after_comment_marker =
 4563                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4564                                if cursor_is_placed_after_comment_marker {
 4565                                    Some(delimiter.clone())
 4566                                } else {
 4567                                    None
 4568                                }
 4569                            });
 4570
 4571                            let mut indent_on_newline = IndentSize::spaces(0);
 4572                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4573
 4574                            let doc_delimiter = maybe!({
 4575                                if !selection_is_empty {
 4576                                    return None;
 4577                                }
 4578
 4579                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4580                                    return None;
 4581                                }
 4582
 4583                                let BlockCommentConfig {
 4584                                    start: start_tag,
 4585                                    end: end_tag,
 4586                                    prefix: delimiter,
 4587                                    tab_size: len,
 4588                                } = language.documentation_comment()?;
 4589                                let is_within_block_comment = buffer
 4590                                    .language_scope_at(start_point)
 4591                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4592                                if !is_within_block_comment {
 4593                                    return None;
 4594                                }
 4595
 4596                                let (snapshot, range) =
 4597                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4598
 4599                                let num_of_whitespaces = snapshot
 4600                                    .chars_for_range(range.clone())
 4601                                    .take_while(|c| c.is_whitespace())
 4602                                    .count();
 4603
 4604                                // 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.
 4605                                let column = start_point.column;
 4606                                let cursor_is_after_start_tag = {
 4607                                    let start_tag_len = start_tag.len();
 4608                                    let start_tag_line = snapshot
 4609                                        .chars_for_range(range.clone())
 4610                                        .skip(num_of_whitespaces)
 4611                                        .take(start_tag_len)
 4612                                        .collect::<String>();
 4613                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4614                                        num_of_whitespaces + start_tag_len <= column as usize
 4615                                    } else {
 4616                                        false
 4617                                    }
 4618                                };
 4619
 4620                                let cursor_is_after_delimiter = {
 4621                                    let delimiter_trim = delimiter.trim_end();
 4622                                    let delimiter_line = snapshot
 4623                                        .chars_for_range(range.clone())
 4624                                        .skip(num_of_whitespaces)
 4625                                        .take(delimiter_trim.len())
 4626                                        .collect::<String>();
 4627                                    if delimiter_line.starts_with(delimiter_trim) {
 4628                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4629                                    } else {
 4630                                        false
 4631                                    }
 4632                                };
 4633
 4634                                let cursor_is_before_end_tag_if_exists = {
 4635                                    let mut char_position = 0u32;
 4636                                    let mut end_tag_offset = None;
 4637
 4638                                    'outer: for chunk in snapshot.text_for_range(range) {
 4639                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4640                                            let chars_before_match =
 4641                                                chunk[..byte_pos].chars().count() as u32;
 4642                                            end_tag_offset =
 4643                                                Some(char_position + chars_before_match);
 4644                                            break 'outer;
 4645                                        }
 4646                                        char_position += chunk.chars().count() as u32;
 4647                                    }
 4648
 4649                                    if let Some(end_tag_offset) = end_tag_offset {
 4650                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4651                                        if cursor_is_after_start_tag {
 4652                                            if cursor_is_before_end_tag {
 4653                                                insert_extra_newline = true;
 4654                                            }
 4655                                            let cursor_is_at_start_of_end_tag =
 4656                                                column == end_tag_offset;
 4657                                            if cursor_is_at_start_of_end_tag {
 4658                                                indent_on_extra_newline.len = *len;
 4659                                            }
 4660                                        }
 4661                                        cursor_is_before_end_tag
 4662                                    } else {
 4663                                        true
 4664                                    }
 4665                                };
 4666
 4667                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4668                                    && cursor_is_before_end_tag_if_exists
 4669                                {
 4670                                    if cursor_is_after_start_tag {
 4671                                        indent_on_newline.len = *len;
 4672                                    }
 4673                                    Some(delimiter.clone())
 4674                                } else {
 4675                                    None
 4676                                }
 4677                            });
 4678
 4679                            (
 4680                                comment_delimiter,
 4681                                doc_delimiter,
 4682                                insert_extra_newline,
 4683                                indent_on_newline,
 4684                                indent_on_extra_newline,
 4685                            )
 4686                        } else {
 4687                            (
 4688                                None,
 4689                                None,
 4690                                false,
 4691                                IndentSize::default(),
 4692                                IndentSize::default(),
 4693                            )
 4694                        };
 4695
 4696                        let prevent_auto_indent = doc_delimiter.is_some();
 4697                        let delimiter = comment_delimiter.or(doc_delimiter);
 4698
 4699                        let capacity_for_delimiter =
 4700                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4701                        let mut new_text = String::with_capacity(
 4702                            1 + capacity_for_delimiter
 4703                                + existing_indent.len as usize
 4704                                + indent_on_newline.len as usize
 4705                                + indent_on_extra_newline.len as usize,
 4706                        );
 4707                        new_text.push('\n');
 4708                        new_text.extend(existing_indent.chars());
 4709                        new_text.extend(indent_on_newline.chars());
 4710
 4711                        if let Some(delimiter) = &delimiter {
 4712                            new_text.push_str(delimiter);
 4713                        }
 4714
 4715                        if insert_extra_newline {
 4716                            new_text.push('\n');
 4717                            new_text.extend(existing_indent.chars());
 4718                            new_text.extend(indent_on_extra_newline.chars());
 4719                        }
 4720
 4721                        let anchor = buffer.anchor_after(end);
 4722                        let new_selection = selection.map(|_| anchor);
 4723                        (
 4724                            ((start..end, new_text), prevent_auto_indent),
 4725                            (insert_extra_newline, new_selection),
 4726                        )
 4727                    })
 4728                    .unzip()
 4729            };
 4730
 4731            let mut auto_indent_edits = Vec::new();
 4732            let mut edits = Vec::new();
 4733            for (edit, prevent_auto_indent) in edits_with_flags {
 4734                if prevent_auto_indent {
 4735                    edits.push(edit);
 4736                } else {
 4737                    auto_indent_edits.push(edit);
 4738                }
 4739            }
 4740            if !edits.is_empty() {
 4741                this.edit(edits, cx);
 4742            }
 4743            if !auto_indent_edits.is_empty() {
 4744                this.edit_with_autoindent(auto_indent_edits, cx);
 4745            }
 4746
 4747            let buffer = this.buffer.read(cx).snapshot(cx);
 4748            let new_selections = selection_info
 4749                .into_iter()
 4750                .map(|(extra_newline_inserted, new_selection)| {
 4751                    let mut cursor = new_selection.end.to_point(&buffer);
 4752                    if extra_newline_inserted {
 4753                        cursor.row -= 1;
 4754                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4755                    }
 4756                    new_selection.map(|_| cursor)
 4757                })
 4758                .collect();
 4759
 4760            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4761            this.refresh_edit_prediction(true, false, window, cx);
 4762        });
 4763    }
 4764
 4765    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4767
 4768        let buffer = self.buffer.read(cx);
 4769        let snapshot = buffer.snapshot(cx);
 4770
 4771        let mut edits = Vec::new();
 4772        let mut rows = Vec::new();
 4773
 4774        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4775            let cursor = selection.head();
 4776            let row = cursor.row;
 4777
 4778            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4779
 4780            let newline = "\n".to_string();
 4781            edits.push((start_of_line..start_of_line, newline));
 4782
 4783            rows.push(row + rows_inserted as u32);
 4784        }
 4785
 4786        self.transact(window, cx, |editor, window, cx| {
 4787            editor.edit(edits, cx);
 4788
 4789            editor.change_selections(Default::default(), window, cx, |s| {
 4790                let mut index = 0;
 4791                s.move_cursors_with(|map, _, _| {
 4792                    let row = rows[index];
 4793                    index += 1;
 4794
 4795                    let point = Point::new(row, 0);
 4796                    let boundary = map.next_line_boundary(point).1;
 4797                    let clipped = map.clip_point(boundary, Bias::Left);
 4798
 4799                    (clipped, SelectionGoal::None)
 4800                });
 4801            });
 4802
 4803            let mut indent_edits = Vec::new();
 4804            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4805            for row in rows {
 4806                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4807                for (row, indent) in indents {
 4808                    if indent.len == 0 {
 4809                        continue;
 4810                    }
 4811
 4812                    let text = match indent.kind {
 4813                        IndentKind::Space => " ".repeat(indent.len as usize),
 4814                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4815                    };
 4816                    let point = Point::new(row.0, 0);
 4817                    indent_edits.push((point..point, text));
 4818                }
 4819            }
 4820            editor.edit(indent_edits, cx);
 4821        });
 4822    }
 4823
 4824    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4826
 4827        let buffer = self.buffer.read(cx);
 4828        let snapshot = buffer.snapshot(cx);
 4829
 4830        let mut edits = Vec::new();
 4831        let mut rows = Vec::new();
 4832        let mut rows_inserted = 0;
 4833
 4834        for selection in self.selections.all_adjusted(cx) {
 4835            let cursor = selection.head();
 4836            let row = cursor.row;
 4837
 4838            let point = Point::new(row + 1, 0);
 4839            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4840
 4841            let newline = "\n".to_string();
 4842            edits.push((start_of_line..start_of_line, newline));
 4843
 4844            rows_inserted += 1;
 4845            rows.push(row + rows_inserted);
 4846        }
 4847
 4848        self.transact(window, cx, |editor, window, cx| {
 4849            editor.edit(edits, cx);
 4850
 4851            editor.change_selections(Default::default(), window, cx, |s| {
 4852                let mut index = 0;
 4853                s.move_cursors_with(|map, _, _| {
 4854                    let row = rows[index];
 4855                    index += 1;
 4856
 4857                    let point = Point::new(row, 0);
 4858                    let boundary = map.next_line_boundary(point).1;
 4859                    let clipped = map.clip_point(boundary, Bias::Left);
 4860
 4861                    (clipped, SelectionGoal::None)
 4862                });
 4863            });
 4864
 4865            let mut indent_edits = Vec::new();
 4866            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4867            for row in rows {
 4868                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4869                for (row, indent) in indents {
 4870                    if indent.len == 0 {
 4871                        continue;
 4872                    }
 4873
 4874                    let text = match indent.kind {
 4875                        IndentKind::Space => " ".repeat(indent.len as usize),
 4876                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4877                    };
 4878                    let point = Point::new(row.0, 0);
 4879                    indent_edits.push((point..point, text));
 4880                }
 4881            }
 4882            editor.edit(indent_edits, cx);
 4883        });
 4884    }
 4885
 4886    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4887        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4888            original_indent_columns: Vec::new(),
 4889        });
 4890        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4891    }
 4892
 4893    fn insert_with_autoindent_mode(
 4894        &mut self,
 4895        text: &str,
 4896        autoindent_mode: Option<AutoindentMode>,
 4897        window: &mut Window,
 4898        cx: &mut Context<Self>,
 4899    ) {
 4900        if self.read_only(cx) {
 4901            return;
 4902        }
 4903
 4904        let text: Arc<str> = text.into();
 4905        self.transact(window, cx, |this, window, cx| {
 4906            let old_selections = this.selections.all_adjusted(cx);
 4907            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4908                let anchors = {
 4909                    let snapshot = buffer.read(cx);
 4910                    old_selections
 4911                        .iter()
 4912                        .map(|s| {
 4913                            let anchor = snapshot.anchor_after(s.head());
 4914                            s.map(|_| anchor)
 4915                        })
 4916                        .collect::<Vec<_>>()
 4917                };
 4918                buffer.edit(
 4919                    old_selections
 4920                        .iter()
 4921                        .map(|s| (s.start..s.end, text.clone())),
 4922                    autoindent_mode,
 4923                    cx,
 4924                );
 4925                anchors
 4926            });
 4927
 4928            this.change_selections(Default::default(), window, cx, |s| {
 4929                s.select_anchors(selection_anchors);
 4930            });
 4931
 4932            cx.notify();
 4933        });
 4934    }
 4935
 4936    fn trigger_completion_on_input(
 4937        &mut self,
 4938        text: &str,
 4939        trigger_in_words: bool,
 4940        window: &mut Window,
 4941        cx: &mut Context<Self>,
 4942    ) {
 4943        let completions_source = self
 4944            .context_menu
 4945            .borrow()
 4946            .as_ref()
 4947            .and_then(|menu| match menu {
 4948                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4949                CodeContextMenu::CodeActions(_) => None,
 4950            });
 4951
 4952        match completions_source {
 4953            Some(CompletionsMenuSource::Words { .. }) => {
 4954                self.open_or_update_completions_menu(
 4955                    Some(CompletionsMenuSource::Words {
 4956                        ignore_threshold: false,
 4957                    }),
 4958                    None,
 4959                    window,
 4960                    cx,
 4961                );
 4962            }
 4963            Some(CompletionsMenuSource::Normal)
 4964            | Some(CompletionsMenuSource::SnippetChoices)
 4965            | None
 4966                if self.is_completion_trigger(
 4967                    text,
 4968                    trigger_in_words,
 4969                    completions_source.is_some(),
 4970                    cx,
 4971                ) =>
 4972            {
 4973                self.show_completions(
 4974                    &ShowCompletions {
 4975                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4976                    },
 4977                    window,
 4978                    cx,
 4979                )
 4980            }
 4981            _ => {
 4982                self.hide_context_menu(window, cx);
 4983            }
 4984        }
 4985    }
 4986
 4987    fn is_completion_trigger(
 4988        &self,
 4989        text: &str,
 4990        trigger_in_words: bool,
 4991        menu_is_open: bool,
 4992        cx: &mut Context<Self>,
 4993    ) -> bool {
 4994        let position = self.selections.newest_anchor().head();
 4995        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4996            return false;
 4997        };
 4998
 4999        if let Some(completion_provider) = &self.completion_provider {
 5000            completion_provider.is_completion_trigger(
 5001                &buffer,
 5002                position.text_anchor,
 5003                text,
 5004                trigger_in_words,
 5005                menu_is_open,
 5006                cx,
 5007            )
 5008        } else {
 5009            false
 5010        }
 5011    }
 5012
 5013    /// If any empty selections is touching the start of its innermost containing autoclose
 5014    /// region, expand it to select the brackets.
 5015    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5016        let selections = self.selections.all::<usize>(cx);
 5017        let buffer = self.buffer.read(cx).read(cx);
 5018        let new_selections = self
 5019            .selections_with_autoclose_regions(selections, &buffer)
 5020            .map(|(mut selection, region)| {
 5021                if !selection.is_empty() {
 5022                    return selection;
 5023                }
 5024
 5025                if let Some(region) = region {
 5026                    let mut range = region.range.to_offset(&buffer);
 5027                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5028                        range.start -= region.pair.start.len();
 5029                        if buffer.contains_str_at(range.start, &region.pair.start)
 5030                            && buffer.contains_str_at(range.end, &region.pair.end)
 5031                        {
 5032                            range.end += region.pair.end.len();
 5033                            selection.start = range.start;
 5034                            selection.end = range.end;
 5035
 5036                            return selection;
 5037                        }
 5038                    }
 5039                }
 5040
 5041                let always_treat_brackets_as_autoclosed = buffer
 5042                    .language_settings_at(selection.start, cx)
 5043                    .always_treat_brackets_as_autoclosed;
 5044
 5045                if !always_treat_brackets_as_autoclosed {
 5046                    return selection;
 5047                }
 5048
 5049                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5050                    for (pair, enabled) in scope.brackets() {
 5051                        if !enabled || !pair.close {
 5052                            continue;
 5053                        }
 5054
 5055                        if buffer.contains_str_at(selection.start, &pair.end) {
 5056                            let pair_start_len = pair.start.len();
 5057                            if buffer.contains_str_at(
 5058                                selection.start.saturating_sub(pair_start_len),
 5059                                &pair.start,
 5060                            ) {
 5061                                selection.start -= pair_start_len;
 5062                                selection.end += pair.end.len();
 5063
 5064                                return selection;
 5065                            }
 5066                        }
 5067                    }
 5068                }
 5069
 5070                selection
 5071            })
 5072            .collect();
 5073
 5074        drop(buffer);
 5075        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5076            selections.select(new_selections)
 5077        });
 5078    }
 5079
 5080    /// Iterate the given selections, and for each one, find the smallest surrounding
 5081    /// autoclose region. This uses the ordering of the selections and the autoclose
 5082    /// regions to avoid repeated comparisons.
 5083    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5084        &'a self,
 5085        selections: impl IntoIterator<Item = Selection<D>>,
 5086        buffer: &'a MultiBufferSnapshot,
 5087    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5088        let mut i = 0;
 5089        let mut regions = self.autoclose_regions.as_slice();
 5090        selections.into_iter().map(move |selection| {
 5091            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5092
 5093            let mut enclosing = None;
 5094            while let Some(pair_state) = regions.get(i) {
 5095                if pair_state.range.end.to_offset(buffer) < range.start {
 5096                    regions = &regions[i + 1..];
 5097                    i = 0;
 5098                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5099                    break;
 5100                } else {
 5101                    if pair_state.selection_id == selection.id {
 5102                        enclosing = Some(pair_state);
 5103                    }
 5104                    i += 1;
 5105                }
 5106            }
 5107
 5108            (selection, enclosing)
 5109        })
 5110    }
 5111
 5112    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5113    fn invalidate_autoclose_regions(
 5114        &mut self,
 5115        mut selections: &[Selection<Anchor>],
 5116        buffer: &MultiBufferSnapshot,
 5117    ) {
 5118        self.autoclose_regions.retain(|state| {
 5119            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5120                return false;
 5121            }
 5122
 5123            let mut i = 0;
 5124            while let Some(selection) = selections.get(i) {
 5125                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5126                    selections = &selections[1..];
 5127                    continue;
 5128                }
 5129                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5130                    break;
 5131                }
 5132                if selection.id == state.selection_id {
 5133                    return true;
 5134                } else {
 5135                    i += 1;
 5136                }
 5137            }
 5138            false
 5139        });
 5140    }
 5141
 5142    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5143        let offset = position.to_offset(buffer);
 5144        let (word_range, kind) =
 5145            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5146        if offset > word_range.start && kind == Some(CharKind::Word) {
 5147            Some(
 5148                buffer
 5149                    .text_for_range(word_range.start..offset)
 5150                    .collect::<String>(),
 5151            )
 5152        } else {
 5153            None
 5154        }
 5155    }
 5156
 5157    pub fn toggle_inline_values(
 5158        &mut self,
 5159        _: &ToggleInlineValues,
 5160        _: &mut Window,
 5161        cx: &mut Context<Self>,
 5162    ) {
 5163        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5164
 5165        self.refresh_inline_values(cx);
 5166    }
 5167
 5168    pub fn toggle_inlay_hints(
 5169        &mut self,
 5170        _: &ToggleInlayHints,
 5171        _: &mut Window,
 5172        cx: &mut Context<Self>,
 5173    ) {
 5174        self.refresh_inlay_hints(
 5175            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5176            cx,
 5177        );
 5178    }
 5179
 5180    pub fn inlay_hints_enabled(&self) -> bool {
 5181        self.inlay_hint_cache.enabled
 5182    }
 5183
 5184    pub fn inline_values_enabled(&self) -> bool {
 5185        self.inline_value_cache.enabled
 5186    }
 5187
 5188    #[cfg(any(test, feature = "test-support"))]
 5189    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5190        self.display_map
 5191            .read(cx)
 5192            .current_inlays()
 5193            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5194            .cloned()
 5195            .collect()
 5196    }
 5197
 5198    #[cfg(any(test, feature = "test-support"))]
 5199    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5200        self.display_map
 5201            .read(cx)
 5202            .current_inlays()
 5203            .cloned()
 5204            .collect()
 5205    }
 5206
 5207    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5208        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5209            return;
 5210        }
 5211
 5212        let reason_description = reason.description();
 5213        let ignore_debounce = matches!(
 5214            reason,
 5215            InlayHintRefreshReason::SettingsChange(_)
 5216                | InlayHintRefreshReason::Toggle(_)
 5217                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5218                | InlayHintRefreshReason::ModifiersChanged(_)
 5219        );
 5220        let (invalidate_cache, required_languages) = match reason {
 5221            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5222                match self.inlay_hint_cache.modifiers_override(enabled) {
 5223                    Some(enabled) => {
 5224                        if enabled {
 5225                            (InvalidationStrategy::RefreshRequested, None)
 5226                        } else {
 5227                            self.clear_inlay_hints(cx);
 5228                            return;
 5229                        }
 5230                    }
 5231                    None => return,
 5232                }
 5233            }
 5234            InlayHintRefreshReason::Toggle(enabled) => {
 5235                if self.inlay_hint_cache.toggle(enabled) {
 5236                    if enabled {
 5237                        (InvalidationStrategy::RefreshRequested, None)
 5238                    } else {
 5239                        self.clear_inlay_hints(cx);
 5240                        return;
 5241                    }
 5242                } else {
 5243                    return;
 5244                }
 5245            }
 5246            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5247                match self.inlay_hint_cache.update_settings(
 5248                    &self.buffer,
 5249                    new_settings,
 5250                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5251                    cx,
 5252                ) {
 5253                    ControlFlow::Break(Some(InlaySplice {
 5254                        to_remove,
 5255                        to_insert,
 5256                    })) => {
 5257                        self.splice_inlays(&to_remove, to_insert, cx);
 5258                        return;
 5259                    }
 5260                    ControlFlow::Break(None) => return,
 5261                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5262                }
 5263            }
 5264            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5265                if let Some(InlaySplice {
 5266                    to_remove,
 5267                    to_insert,
 5268                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5269                {
 5270                    self.splice_inlays(&to_remove, to_insert, cx);
 5271                }
 5272                self.display_map.update(cx, |display_map, _| {
 5273                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5274                });
 5275                return;
 5276            }
 5277            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5278            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5279                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5280            }
 5281            InlayHintRefreshReason::RefreshRequested => {
 5282                (InvalidationStrategy::RefreshRequested, None)
 5283            }
 5284        };
 5285
 5286        let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
 5287        visible_excerpts.retain(|_, (buffer, _, _)| {
 5288            self.registered_buffers
 5289                .contains_key(&buffer.read(cx).remote_id())
 5290        });
 5291
 5292        if let Some(InlaySplice {
 5293            to_remove,
 5294            to_insert,
 5295        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5296            reason_description,
 5297            visible_excerpts,
 5298            invalidate_cache,
 5299            ignore_debounce,
 5300            cx,
 5301        ) {
 5302            self.splice_inlays(&to_remove, to_insert, cx);
 5303        }
 5304    }
 5305
 5306    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5307        self.splice_inlays(
 5308            &self
 5309                .visible_inlay_hints(cx)
 5310                .map(|inlay| inlay.id)
 5311                .collect::<Vec<_>>(),
 5312            Vec::new(),
 5313            cx,
 5314        );
 5315    }
 5316
 5317    fn visible_inlay_hints<'a>(
 5318        &'a self,
 5319        cx: &'a Context<Editor>,
 5320    ) -> impl Iterator<Item = &'a Inlay> {
 5321        self.display_map
 5322            .read(cx)
 5323            .current_inlays()
 5324            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5325    }
 5326
 5327    pub fn visible_excerpts(
 5328        &self,
 5329        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5330        cx: &mut Context<Editor>,
 5331    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5332        let Some(project) = self.project() else {
 5333            return HashMap::default();
 5334        };
 5335        let project = project.read(cx);
 5336        let multi_buffer = self.buffer().read(cx);
 5337        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5338        let multi_buffer_visible_start = self
 5339            .scroll_manager
 5340            .anchor()
 5341            .anchor
 5342            .to_point(&multi_buffer_snapshot);
 5343        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5344            multi_buffer_visible_start
 5345                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5346            Bias::Left,
 5347        );
 5348        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5349        multi_buffer_snapshot
 5350            .range_to_buffer_ranges(multi_buffer_visible_range)
 5351            .into_iter()
 5352            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5353            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5354                let buffer_file = project::File::from_dyn(buffer.file())?;
 5355                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5356                let worktree_entry = buffer_worktree
 5357                    .read(cx)
 5358                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5359                if worktree_entry.is_ignored {
 5360                    return None;
 5361                }
 5362
 5363                let language = buffer.language()?;
 5364                if let Some(restrict_to_languages) = restrict_to_languages
 5365                    && !restrict_to_languages.contains(language)
 5366                {
 5367                    return None;
 5368                }
 5369                Some((
 5370                    excerpt_id,
 5371                    (
 5372                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5373                        buffer.version().clone(),
 5374                        excerpt_visible_range,
 5375                    ),
 5376                ))
 5377            })
 5378            .collect()
 5379    }
 5380
 5381    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5382        TextLayoutDetails {
 5383            text_system: window.text_system().clone(),
 5384            editor_style: self.style.clone().unwrap(),
 5385            rem_size: window.rem_size(),
 5386            scroll_anchor: self.scroll_manager.anchor(),
 5387            visible_rows: self.visible_line_count(),
 5388            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5389        }
 5390    }
 5391
 5392    pub fn splice_inlays(
 5393        &self,
 5394        to_remove: &[InlayId],
 5395        to_insert: Vec<Inlay>,
 5396        cx: &mut Context<Self>,
 5397    ) {
 5398        self.display_map.update(cx, |display_map, cx| {
 5399            display_map.splice_inlays(to_remove, to_insert, cx)
 5400        });
 5401        cx.notify();
 5402    }
 5403
 5404    fn trigger_on_type_formatting(
 5405        &self,
 5406        input: String,
 5407        window: &mut Window,
 5408        cx: &mut Context<Self>,
 5409    ) -> Option<Task<Result<()>>> {
 5410        if input.len() != 1 {
 5411            return None;
 5412        }
 5413
 5414        let project = self.project()?;
 5415        let position = self.selections.newest_anchor().head();
 5416        let (buffer, buffer_position) = self
 5417            .buffer
 5418            .read(cx)
 5419            .text_anchor_for_position(position, cx)?;
 5420
 5421        let settings = language_settings::language_settings(
 5422            buffer
 5423                .read(cx)
 5424                .language_at(buffer_position)
 5425                .map(|l| l.name()),
 5426            buffer.read(cx).file(),
 5427            cx,
 5428        );
 5429        if !settings.use_on_type_format {
 5430            return None;
 5431        }
 5432
 5433        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5434        // hence we do LSP request & edit on host side only — add formats to host's history.
 5435        let push_to_lsp_host_history = true;
 5436        // If this is not the host, append its history with new edits.
 5437        let push_to_client_history = project.read(cx).is_via_collab();
 5438
 5439        let on_type_formatting = project.update(cx, |project, cx| {
 5440            project.on_type_format(
 5441                buffer.clone(),
 5442                buffer_position,
 5443                input,
 5444                push_to_lsp_host_history,
 5445                cx,
 5446            )
 5447        });
 5448        Some(cx.spawn_in(window, async move |editor, cx| {
 5449            if let Some(transaction) = on_type_formatting.await? {
 5450                if push_to_client_history {
 5451                    buffer
 5452                        .update(cx, |buffer, _| {
 5453                            buffer.push_transaction(transaction, Instant::now());
 5454                            buffer.finalize_last_transaction();
 5455                        })
 5456                        .ok();
 5457                }
 5458                editor.update(cx, |editor, cx| {
 5459                    editor.refresh_document_highlights(cx);
 5460                })?;
 5461            }
 5462            Ok(())
 5463        }))
 5464    }
 5465
 5466    pub fn show_word_completions(
 5467        &mut self,
 5468        _: &ShowWordCompletions,
 5469        window: &mut Window,
 5470        cx: &mut Context<Self>,
 5471    ) {
 5472        self.open_or_update_completions_menu(
 5473            Some(CompletionsMenuSource::Words {
 5474                ignore_threshold: true,
 5475            }),
 5476            None,
 5477            window,
 5478            cx,
 5479        );
 5480    }
 5481
 5482    pub fn show_completions(
 5483        &mut self,
 5484        options: &ShowCompletions,
 5485        window: &mut Window,
 5486        cx: &mut Context<Self>,
 5487    ) {
 5488        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5489    }
 5490
 5491    fn open_or_update_completions_menu(
 5492        &mut self,
 5493        requested_source: Option<CompletionsMenuSource>,
 5494        trigger: Option<&str>,
 5495        window: &mut Window,
 5496        cx: &mut Context<Self>,
 5497    ) {
 5498        if self.pending_rename.is_some() {
 5499            return;
 5500        }
 5501
 5502        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5503
 5504        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5505        // inserted and selected. To handle that case, the start of the selection is used so that
 5506        // the menu starts with all choices.
 5507        let position = self
 5508            .selections
 5509            .newest_anchor()
 5510            .start
 5511            .bias_right(&multibuffer_snapshot);
 5512        if position.diff_base_anchor.is_some() {
 5513            return;
 5514        }
 5515        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5516        let Some(buffer) = buffer_position
 5517            .buffer_id
 5518            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5519        else {
 5520            return;
 5521        };
 5522        let buffer_snapshot = buffer.read(cx).snapshot();
 5523
 5524        let query: Option<Arc<String>> =
 5525            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5526                .map(|query| query.into());
 5527
 5528        drop(multibuffer_snapshot);
 5529
 5530        // Hide the current completions menu when query is empty. Without this, cached
 5531        // completions from before the trigger char may be reused (#32774).
 5532        if query.is_none() {
 5533            let menu_is_open = matches!(
 5534                self.context_menu.borrow().as_ref(),
 5535                Some(CodeContextMenu::Completions(_))
 5536            );
 5537            if menu_is_open {
 5538                self.hide_context_menu(window, cx);
 5539            }
 5540        }
 5541
 5542        let mut ignore_word_threshold = false;
 5543        let provider = match requested_source {
 5544            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5545            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5546                ignore_word_threshold = ignore_threshold;
 5547                None
 5548            }
 5549            Some(CompletionsMenuSource::SnippetChoices) => {
 5550                log::error!("bug: SnippetChoices requested_source is not handled");
 5551                None
 5552            }
 5553        };
 5554
 5555        let sort_completions = provider
 5556            .as_ref()
 5557            .is_some_and(|provider| provider.sort_completions());
 5558
 5559        let filter_completions = provider
 5560            .as_ref()
 5561            .is_none_or(|provider| provider.filter_completions());
 5562
 5563        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5564            if filter_completions {
 5565                menu.filter(query.clone(), provider.clone(), window, cx);
 5566            }
 5567            // When `is_incomplete` is false, no need to re-query completions when the current query
 5568            // is a suffix of the initial query.
 5569            if !menu.is_incomplete {
 5570                // If the new query is a suffix of the old query (typing more characters) and
 5571                // the previous result was complete, the existing completions can be filtered.
 5572                //
 5573                // Note that this is always true for snippet completions.
 5574                let query_matches = match (&menu.initial_query, &query) {
 5575                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5576                    (None, _) => true,
 5577                    _ => false,
 5578                };
 5579                if query_matches {
 5580                    let position_matches = if menu.initial_position == position {
 5581                        true
 5582                    } else {
 5583                        let snapshot = self.buffer.read(cx).read(cx);
 5584                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5585                    };
 5586                    if position_matches {
 5587                        return;
 5588                    }
 5589                }
 5590            }
 5591        };
 5592
 5593        let trigger_kind = match trigger {
 5594            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5595                CompletionTriggerKind::TRIGGER_CHARACTER
 5596            }
 5597            _ => CompletionTriggerKind::INVOKED,
 5598        };
 5599        let completion_context = CompletionContext {
 5600            trigger_character: trigger.and_then(|trigger| {
 5601                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5602                    Some(String::from(trigger))
 5603                } else {
 5604                    None
 5605                }
 5606            }),
 5607            trigger_kind,
 5608        };
 5609
 5610        let Anchor {
 5611            excerpt_id: buffer_excerpt_id,
 5612            text_anchor: buffer_position,
 5613            ..
 5614        } = buffer_position;
 5615
 5616        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5617            buffer_snapshot.surrounding_word(buffer_position, None)
 5618        {
 5619            let word_to_exclude = buffer_snapshot
 5620                .text_for_range(word_range.clone())
 5621                .collect::<String>();
 5622            (
 5623                buffer_snapshot.anchor_before(word_range.start)
 5624                    ..buffer_snapshot.anchor_after(buffer_position),
 5625                Some(word_to_exclude),
 5626            )
 5627        } else {
 5628            (buffer_position..buffer_position, None)
 5629        };
 5630
 5631        let language = buffer_snapshot
 5632            .language_at(buffer_position)
 5633            .map(|language| language.name());
 5634
 5635        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5636            .completions
 5637            .clone();
 5638
 5639        let show_completion_documentation = buffer_snapshot
 5640            .settings_at(buffer_position, cx)
 5641            .show_completion_documentation;
 5642
 5643        // The document can be large, so stay in reasonable bounds when searching for words,
 5644        // otherwise completion pop-up might be slow to appear.
 5645        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5646        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5647        let min_word_search = buffer_snapshot.clip_point(
 5648            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5649            Bias::Left,
 5650        );
 5651        let max_word_search = buffer_snapshot.clip_point(
 5652            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5653            Bias::Right,
 5654        );
 5655        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5656            ..buffer_snapshot.point_to_offset(max_word_search);
 5657
 5658        let skip_digits = query
 5659            .as_ref()
 5660            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5661
 5662        let omit_word_completions = !self.word_completions_enabled
 5663            || (!ignore_word_threshold
 5664                && match &query {
 5665                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5666                    None => completion_settings.words_min_length != 0,
 5667                });
 5668
 5669        let (mut words, provider_responses) = match &provider {
 5670            Some(provider) => {
 5671                let provider_responses = provider.completions(
 5672                    buffer_excerpt_id,
 5673                    &buffer,
 5674                    buffer_position,
 5675                    completion_context,
 5676                    window,
 5677                    cx,
 5678                );
 5679
 5680                let words = match (omit_word_completions, completion_settings.words) {
 5681                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5682                        Task::ready(BTreeMap::default())
 5683                    }
 5684                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5685                        .background_spawn(async move {
 5686                            buffer_snapshot.words_in_range(WordsQuery {
 5687                                fuzzy_contents: None,
 5688                                range: word_search_range,
 5689                                skip_digits,
 5690                            })
 5691                        }),
 5692                };
 5693
 5694                (words, provider_responses)
 5695            }
 5696            None => {
 5697                let words = if omit_word_completions {
 5698                    Task::ready(BTreeMap::default())
 5699                } else {
 5700                    cx.background_spawn(async move {
 5701                        buffer_snapshot.words_in_range(WordsQuery {
 5702                            fuzzy_contents: None,
 5703                            range: word_search_range,
 5704                            skip_digits,
 5705                        })
 5706                    })
 5707                };
 5708                (words, Task::ready(Ok(Vec::new())))
 5709            }
 5710        };
 5711
 5712        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5713
 5714        let id = post_inc(&mut self.next_completion_id);
 5715        let task = cx.spawn_in(window, async move |editor, cx| {
 5716            let Ok(()) = editor.update(cx, |this, _| {
 5717                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5718            }) else {
 5719                return;
 5720            };
 5721
 5722            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5723            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5724            let mut completions = Vec::new();
 5725            let mut is_incomplete = false;
 5726            let mut display_options: Option<CompletionDisplayOptions> = None;
 5727            if let Some(provider_responses) = provider_responses.await.log_err()
 5728                && !provider_responses.is_empty()
 5729            {
 5730                for response in provider_responses {
 5731                    completions.extend(response.completions);
 5732                    is_incomplete = is_incomplete || response.is_incomplete;
 5733                    match display_options.as_mut() {
 5734                        None => {
 5735                            display_options = Some(response.display_options);
 5736                        }
 5737                        Some(options) => options.merge(&response.display_options),
 5738                    }
 5739                }
 5740                if completion_settings.words == WordsCompletionMode::Fallback {
 5741                    words = Task::ready(BTreeMap::default());
 5742                }
 5743            }
 5744            let display_options = display_options.unwrap_or_default();
 5745
 5746            let mut words = words.await;
 5747            if let Some(word_to_exclude) = &word_to_exclude {
 5748                words.remove(word_to_exclude);
 5749            }
 5750            for lsp_completion in &completions {
 5751                words.remove(&lsp_completion.new_text);
 5752            }
 5753            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5754                replace_range: word_replace_range.clone(),
 5755                new_text: word.clone(),
 5756                label: CodeLabel::plain(word, None),
 5757                icon_path: None,
 5758                documentation: None,
 5759                source: CompletionSource::BufferWord {
 5760                    word_range,
 5761                    resolved: false,
 5762                },
 5763                insert_text_mode: Some(InsertTextMode::AS_IS),
 5764                confirm: None,
 5765            }));
 5766
 5767            let menu = if completions.is_empty() {
 5768                None
 5769            } else {
 5770                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5771                    let languages = editor
 5772                        .workspace
 5773                        .as_ref()
 5774                        .and_then(|(workspace, _)| workspace.upgrade())
 5775                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5776                    let menu = CompletionsMenu::new(
 5777                        id,
 5778                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5779                        sort_completions,
 5780                        show_completion_documentation,
 5781                        position,
 5782                        query.clone(),
 5783                        is_incomplete,
 5784                        buffer.clone(),
 5785                        completions.into(),
 5786                        display_options,
 5787                        snippet_sort_order,
 5788                        languages,
 5789                        language,
 5790                        cx,
 5791                    );
 5792
 5793                    let query = if filter_completions { query } else { None };
 5794                    let matches_task = if let Some(query) = query {
 5795                        menu.do_async_filtering(query, cx)
 5796                    } else {
 5797                        Task::ready(menu.unfiltered_matches())
 5798                    };
 5799                    (menu, matches_task)
 5800                }) else {
 5801                    return;
 5802                };
 5803
 5804                let matches = matches_task.await;
 5805
 5806                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5807                    // Newer menu already set, so exit.
 5808                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5809                        editor.context_menu.borrow().as_ref()
 5810                        && prev_menu.id > id
 5811                    {
 5812                        return;
 5813                    };
 5814
 5815                    // Only valid to take prev_menu because it the new menu is immediately set
 5816                    // below, or the menu is hidden.
 5817                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5818                        editor.context_menu.borrow_mut().take()
 5819                    {
 5820                        let position_matches =
 5821                            if prev_menu.initial_position == menu.initial_position {
 5822                                true
 5823                            } else {
 5824                                let snapshot = editor.buffer.read(cx).read(cx);
 5825                                prev_menu.initial_position.to_offset(&snapshot)
 5826                                    == menu.initial_position.to_offset(&snapshot)
 5827                            };
 5828                        if position_matches {
 5829                            // Preserve markdown cache before `set_filter_results` because it will
 5830                            // try to populate the documentation cache.
 5831                            menu.preserve_markdown_cache(prev_menu);
 5832                        }
 5833                    };
 5834
 5835                    menu.set_filter_results(matches, provider, window, cx);
 5836                }) else {
 5837                    return;
 5838                };
 5839
 5840                menu.visible().then_some(menu)
 5841            };
 5842
 5843            editor
 5844                .update_in(cx, |editor, window, cx| {
 5845                    if editor.focus_handle.is_focused(window)
 5846                        && let Some(menu) = menu
 5847                    {
 5848                        *editor.context_menu.borrow_mut() =
 5849                            Some(CodeContextMenu::Completions(menu));
 5850
 5851                        crate::hover_popover::hide_hover(editor, cx);
 5852                        if editor.show_edit_predictions_in_menu() {
 5853                            editor.update_visible_edit_prediction(window, cx);
 5854                        } else {
 5855                            editor.discard_edit_prediction(false, cx);
 5856                        }
 5857
 5858                        cx.notify();
 5859                        return;
 5860                    }
 5861
 5862                    if editor.completion_tasks.len() <= 1 {
 5863                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5864                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5865                        // If it was already hidden and we don't show edit predictions in the menu,
 5866                        // we should also show the edit prediction when available.
 5867                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5868                            editor.update_visible_edit_prediction(window, cx);
 5869                        }
 5870                    }
 5871                })
 5872                .ok();
 5873        });
 5874
 5875        self.completion_tasks.push((id, task));
 5876    }
 5877
 5878    #[cfg(feature = "test-support")]
 5879    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5880        let menu = self.context_menu.borrow();
 5881        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5882            let completions = menu.completions.borrow();
 5883            Some(completions.to_vec())
 5884        } else {
 5885            None
 5886        }
 5887    }
 5888
 5889    pub fn with_completions_menu_matching_id<R>(
 5890        &self,
 5891        id: CompletionId,
 5892        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5893    ) -> R {
 5894        let mut context_menu = self.context_menu.borrow_mut();
 5895        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5896            return f(None);
 5897        };
 5898        if completions_menu.id != id {
 5899            return f(None);
 5900        }
 5901        f(Some(completions_menu))
 5902    }
 5903
 5904    pub fn confirm_completion(
 5905        &mut self,
 5906        action: &ConfirmCompletion,
 5907        window: &mut Window,
 5908        cx: &mut Context<Self>,
 5909    ) -> Option<Task<Result<()>>> {
 5910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5911        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5912    }
 5913
 5914    pub fn confirm_completion_insert(
 5915        &mut self,
 5916        _: &ConfirmCompletionInsert,
 5917        window: &mut Window,
 5918        cx: &mut Context<Self>,
 5919    ) -> Option<Task<Result<()>>> {
 5920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5921        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5922    }
 5923
 5924    pub fn confirm_completion_replace(
 5925        &mut self,
 5926        _: &ConfirmCompletionReplace,
 5927        window: &mut Window,
 5928        cx: &mut Context<Self>,
 5929    ) -> Option<Task<Result<()>>> {
 5930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5931        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5932    }
 5933
 5934    pub fn compose_completion(
 5935        &mut self,
 5936        action: &ComposeCompletion,
 5937        window: &mut Window,
 5938        cx: &mut Context<Self>,
 5939    ) -> Option<Task<Result<()>>> {
 5940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5941        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5942    }
 5943
 5944    fn do_completion(
 5945        &mut self,
 5946        item_ix: Option<usize>,
 5947        intent: CompletionIntent,
 5948        window: &mut Window,
 5949        cx: &mut Context<Editor>,
 5950    ) -> Option<Task<Result<()>>> {
 5951        use language::ToOffset as _;
 5952
 5953        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5954        else {
 5955            return None;
 5956        };
 5957
 5958        let candidate_id = {
 5959            let entries = completions_menu.entries.borrow();
 5960            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5961            if self.show_edit_predictions_in_menu() {
 5962                self.discard_edit_prediction(true, cx);
 5963            }
 5964            mat.candidate_id
 5965        };
 5966
 5967        let completion = completions_menu
 5968            .completions
 5969            .borrow()
 5970            .get(candidate_id)?
 5971            .clone();
 5972        cx.stop_propagation();
 5973
 5974        let buffer_handle = completions_menu.buffer.clone();
 5975
 5976        let CompletionEdit {
 5977            new_text,
 5978            snippet,
 5979            replace_range,
 5980        } = process_completion_for_edit(
 5981            &completion,
 5982            intent,
 5983            &buffer_handle,
 5984            &completions_menu.initial_position.text_anchor,
 5985            cx,
 5986        );
 5987
 5988        let buffer = buffer_handle.read(cx);
 5989        let snapshot = self.buffer.read(cx).snapshot(cx);
 5990        let newest_anchor = self.selections.newest_anchor();
 5991        let replace_range_multibuffer = {
 5992            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5993            let multibuffer_anchor = snapshot
 5994                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5995                .unwrap()
 5996                ..snapshot
 5997                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5998                    .unwrap();
 5999            multibuffer_anchor.start.to_offset(&snapshot)
 6000                ..multibuffer_anchor.end.to_offset(&snapshot)
 6001        };
 6002        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6003            return None;
 6004        }
 6005
 6006        let old_text = buffer
 6007            .text_for_range(replace_range.clone())
 6008            .collect::<String>();
 6009        let lookbehind = newest_anchor
 6010            .start
 6011            .text_anchor
 6012            .to_offset(buffer)
 6013            .saturating_sub(replace_range.start);
 6014        let lookahead = replace_range
 6015            .end
 6016            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6017        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6018        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6019
 6020        let selections = self.selections.all::<usize>(cx);
 6021        let mut ranges = Vec::new();
 6022        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6023
 6024        for selection in &selections {
 6025            let range = if selection.id == newest_anchor.id {
 6026                replace_range_multibuffer.clone()
 6027            } else {
 6028                let mut range = selection.range();
 6029
 6030                // if prefix is present, don't duplicate it
 6031                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6032                    range.start = range.start.saturating_sub(lookbehind);
 6033
 6034                    // if suffix is also present, mimic the newest cursor and replace it
 6035                    if selection.id != newest_anchor.id
 6036                        && snapshot.contains_str_at(range.end, suffix)
 6037                    {
 6038                        range.end += lookahead;
 6039                    }
 6040                }
 6041                range
 6042            };
 6043
 6044            ranges.push(range.clone());
 6045
 6046            if !self.linked_edit_ranges.is_empty() {
 6047                let start_anchor = snapshot.anchor_before(range.start);
 6048                let end_anchor = snapshot.anchor_after(range.end);
 6049                if let Some(ranges) = self
 6050                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6051                {
 6052                    for (buffer, edits) in ranges {
 6053                        linked_edits
 6054                            .entry(buffer.clone())
 6055                            .or_default()
 6056                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6057                    }
 6058                }
 6059            }
 6060        }
 6061
 6062        let common_prefix_len = old_text
 6063            .chars()
 6064            .zip(new_text.chars())
 6065            .take_while(|(a, b)| a == b)
 6066            .map(|(a, _)| a.len_utf8())
 6067            .sum::<usize>();
 6068
 6069        cx.emit(EditorEvent::InputHandled {
 6070            utf16_range_to_replace: None,
 6071            text: new_text[common_prefix_len..].into(),
 6072        });
 6073
 6074        self.transact(window, cx, |editor, window, cx| {
 6075            if let Some(mut snippet) = snippet {
 6076                snippet.text = new_text.to_string();
 6077                editor
 6078                    .insert_snippet(&ranges, snippet, window, cx)
 6079                    .log_err();
 6080            } else {
 6081                editor.buffer.update(cx, |multi_buffer, cx| {
 6082                    let auto_indent = match completion.insert_text_mode {
 6083                        Some(InsertTextMode::AS_IS) => None,
 6084                        _ => editor.autoindent_mode.clone(),
 6085                    };
 6086                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6087                    multi_buffer.edit(edits, auto_indent, cx);
 6088                });
 6089            }
 6090            for (buffer, edits) in linked_edits {
 6091                buffer.update(cx, |buffer, cx| {
 6092                    let snapshot = buffer.snapshot();
 6093                    let edits = edits
 6094                        .into_iter()
 6095                        .map(|(range, text)| {
 6096                            use text::ToPoint as TP;
 6097                            let end_point = TP::to_point(&range.end, &snapshot);
 6098                            let start_point = TP::to_point(&range.start, &snapshot);
 6099                            (start_point..end_point, text)
 6100                        })
 6101                        .sorted_by_key(|(range, _)| range.start);
 6102                    buffer.edit(edits, None, cx);
 6103                })
 6104            }
 6105
 6106            editor.refresh_edit_prediction(true, false, window, cx);
 6107        });
 6108        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6109
 6110        let show_new_completions_on_confirm = completion
 6111            .confirm
 6112            .as_ref()
 6113            .is_some_and(|confirm| confirm(intent, window, cx));
 6114        if show_new_completions_on_confirm {
 6115            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6116        }
 6117
 6118        let provider = self.completion_provider.as_ref()?;
 6119        drop(completion);
 6120        let apply_edits = provider.apply_additional_edits_for_completion(
 6121            buffer_handle,
 6122            completions_menu.completions.clone(),
 6123            candidate_id,
 6124            true,
 6125            cx,
 6126        );
 6127
 6128        let editor_settings = EditorSettings::get_global(cx);
 6129        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6130            // After the code completion is finished, users often want to know what signatures are needed.
 6131            // so we should automatically call signature_help
 6132            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6133        }
 6134
 6135        Some(cx.foreground_executor().spawn(async move {
 6136            apply_edits.await?;
 6137            Ok(())
 6138        }))
 6139    }
 6140
 6141    pub fn toggle_code_actions(
 6142        &mut self,
 6143        action: &ToggleCodeActions,
 6144        window: &mut Window,
 6145        cx: &mut Context<Self>,
 6146    ) {
 6147        let quick_launch = action.quick_launch;
 6148        let mut context_menu = self.context_menu.borrow_mut();
 6149        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6150            if code_actions.deployed_from == action.deployed_from {
 6151                // Toggle if we're selecting the same one
 6152                *context_menu = None;
 6153                cx.notify();
 6154                return;
 6155            } else {
 6156                // Otherwise, clear it and start a new one
 6157                *context_menu = None;
 6158                cx.notify();
 6159            }
 6160        }
 6161        drop(context_menu);
 6162        let snapshot = self.snapshot(window, cx);
 6163        let deployed_from = action.deployed_from.clone();
 6164        let action = action.clone();
 6165        self.completion_tasks.clear();
 6166        self.discard_edit_prediction(false, cx);
 6167
 6168        let multibuffer_point = match &action.deployed_from {
 6169            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6170                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6171            }
 6172            _ => self.selections.newest::<Point>(cx).head(),
 6173        };
 6174        let Some((buffer, buffer_row)) = snapshot
 6175            .buffer_snapshot()
 6176            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6177            .and_then(|(buffer_snapshot, range)| {
 6178                self.buffer()
 6179                    .read(cx)
 6180                    .buffer(buffer_snapshot.remote_id())
 6181                    .map(|buffer| (buffer, range.start.row))
 6182            })
 6183        else {
 6184            return;
 6185        };
 6186        let buffer_id = buffer.read(cx).remote_id();
 6187        let tasks = self
 6188            .tasks
 6189            .get(&(buffer_id, buffer_row))
 6190            .map(|t| Arc::new(t.to_owned()));
 6191
 6192        if !self.focus_handle.is_focused(window) {
 6193            return;
 6194        }
 6195        let project = self.project.clone();
 6196
 6197        let code_actions_task = match deployed_from {
 6198            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6199            _ => self.code_actions(buffer_row, window, cx),
 6200        };
 6201
 6202        let runnable_task = match deployed_from {
 6203            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6204            _ => {
 6205                let mut task_context_task = Task::ready(None);
 6206                if let Some(tasks) = &tasks
 6207                    && let Some(project) = project
 6208                {
 6209                    task_context_task =
 6210                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6211                }
 6212
 6213                cx.spawn_in(window, {
 6214                    let buffer = buffer.clone();
 6215                    async move |editor, cx| {
 6216                        let task_context = task_context_task.await;
 6217
 6218                        let resolved_tasks =
 6219                            tasks
 6220                                .zip(task_context.clone())
 6221                                .map(|(tasks, task_context)| ResolvedTasks {
 6222                                    templates: tasks.resolve(&task_context).collect(),
 6223                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6224                                        multibuffer_point.row,
 6225                                        tasks.column,
 6226                                    )),
 6227                                });
 6228                        let debug_scenarios = editor
 6229                            .update(cx, |editor, cx| {
 6230                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6231                            })?
 6232                            .await;
 6233                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6234                    }
 6235                })
 6236            }
 6237        };
 6238
 6239        cx.spawn_in(window, async move |editor, cx| {
 6240            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6241            let code_actions = code_actions_task.await;
 6242            let spawn_straight_away = quick_launch
 6243                && resolved_tasks
 6244                    .as_ref()
 6245                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6246                && code_actions
 6247                    .as_ref()
 6248                    .is_none_or(|actions| actions.is_empty())
 6249                && debug_scenarios.is_empty();
 6250
 6251            editor.update_in(cx, |editor, window, cx| {
 6252                crate::hover_popover::hide_hover(editor, cx);
 6253                let actions = CodeActionContents::new(
 6254                    resolved_tasks,
 6255                    code_actions,
 6256                    debug_scenarios,
 6257                    task_context.unwrap_or_default(),
 6258                );
 6259
 6260                // Don't show the menu if there are no actions available
 6261                if actions.is_empty() {
 6262                    cx.notify();
 6263                    return Task::ready(Ok(()));
 6264                }
 6265
 6266                *editor.context_menu.borrow_mut() =
 6267                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6268                        buffer,
 6269                        actions,
 6270                        selected_item: Default::default(),
 6271                        scroll_handle: UniformListScrollHandle::default(),
 6272                        deployed_from,
 6273                    }));
 6274                cx.notify();
 6275                if spawn_straight_away
 6276                    && let Some(task) = editor.confirm_code_action(
 6277                        &ConfirmCodeAction { item_ix: Some(0) },
 6278                        window,
 6279                        cx,
 6280                    )
 6281                {
 6282                    return task;
 6283                }
 6284
 6285                Task::ready(Ok(()))
 6286            })
 6287        })
 6288        .detach_and_log_err(cx);
 6289    }
 6290
 6291    fn debug_scenarios(
 6292        &mut self,
 6293        resolved_tasks: &Option<ResolvedTasks>,
 6294        buffer: &Entity<Buffer>,
 6295        cx: &mut App,
 6296    ) -> Task<Vec<task::DebugScenario>> {
 6297        maybe!({
 6298            let project = self.project()?;
 6299            let dap_store = project.read(cx).dap_store();
 6300            let mut scenarios = vec![];
 6301            let resolved_tasks = resolved_tasks.as_ref()?;
 6302            let buffer = buffer.read(cx);
 6303            let language = buffer.language()?;
 6304            let file = buffer.file();
 6305            let debug_adapter = language_settings(language.name().into(), file, cx)
 6306                .debuggers
 6307                .first()
 6308                .map(SharedString::from)
 6309                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6310
 6311            dap_store.update(cx, |dap_store, cx| {
 6312                for (_, task) in &resolved_tasks.templates {
 6313                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6314                        task.original_task().clone(),
 6315                        debug_adapter.clone().into(),
 6316                        task.display_label().to_owned().into(),
 6317                        cx,
 6318                    );
 6319                    scenarios.push(maybe_scenario);
 6320                }
 6321            });
 6322            Some(cx.background_spawn(async move {
 6323                futures::future::join_all(scenarios)
 6324                    .await
 6325                    .into_iter()
 6326                    .flatten()
 6327                    .collect::<Vec<_>>()
 6328            }))
 6329        })
 6330        .unwrap_or_else(|| Task::ready(vec![]))
 6331    }
 6332
 6333    fn code_actions(
 6334        &mut self,
 6335        buffer_row: u32,
 6336        window: &mut Window,
 6337        cx: &mut Context<Self>,
 6338    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6339        let mut task = self.code_actions_task.take();
 6340        cx.spawn_in(window, async move |editor, cx| {
 6341            while let Some(prev_task) = task {
 6342                prev_task.await.log_err();
 6343                task = editor
 6344                    .update(cx, |this, _| this.code_actions_task.take())
 6345                    .ok()?;
 6346            }
 6347
 6348            editor
 6349                .update(cx, |editor, cx| {
 6350                    editor
 6351                        .available_code_actions
 6352                        .clone()
 6353                        .and_then(|(location, code_actions)| {
 6354                            let snapshot = location.buffer.read(cx).snapshot();
 6355                            let point_range = location.range.to_point(&snapshot);
 6356                            let point_range = point_range.start.row..=point_range.end.row;
 6357                            if point_range.contains(&buffer_row) {
 6358                                Some(code_actions)
 6359                            } else {
 6360                                None
 6361                            }
 6362                        })
 6363                })
 6364                .ok()
 6365                .flatten()
 6366        })
 6367    }
 6368
 6369    pub fn confirm_code_action(
 6370        &mut self,
 6371        action: &ConfirmCodeAction,
 6372        window: &mut Window,
 6373        cx: &mut Context<Self>,
 6374    ) -> Option<Task<Result<()>>> {
 6375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6376
 6377        let actions_menu =
 6378            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6379                menu
 6380            } else {
 6381                return None;
 6382            };
 6383
 6384        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6385        let action = actions_menu.actions.get(action_ix)?;
 6386        let title = action.label();
 6387        let buffer = actions_menu.buffer;
 6388        let workspace = self.workspace()?;
 6389
 6390        match action {
 6391            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6392                workspace.update(cx, |workspace, cx| {
 6393                    workspace.schedule_resolved_task(
 6394                        task_source_kind,
 6395                        resolved_task,
 6396                        false,
 6397                        window,
 6398                        cx,
 6399                    );
 6400
 6401                    Some(Task::ready(Ok(())))
 6402                })
 6403            }
 6404            CodeActionsItem::CodeAction {
 6405                excerpt_id,
 6406                action,
 6407                provider,
 6408            } => {
 6409                let apply_code_action =
 6410                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6411                let workspace = workspace.downgrade();
 6412                Some(cx.spawn_in(window, async move |editor, cx| {
 6413                    let project_transaction = apply_code_action.await?;
 6414                    Self::open_project_transaction(
 6415                        &editor,
 6416                        workspace,
 6417                        project_transaction,
 6418                        title,
 6419                        cx,
 6420                    )
 6421                    .await
 6422                }))
 6423            }
 6424            CodeActionsItem::DebugScenario(scenario) => {
 6425                let context = actions_menu.actions.context;
 6426
 6427                workspace.update(cx, |workspace, cx| {
 6428                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6429                    workspace.start_debug_session(
 6430                        scenario,
 6431                        context,
 6432                        Some(buffer),
 6433                        None,
 6434                        window,
 6435                        cx,
 6436                    );
 6437                });
 6438                Some(Task::ready(Ok(())))
 6439            }
 6440        }
 6441    }
 6442
 6443    pub async fn open_project_transaction(
 6444        editor: &WeakEntity<Editor>,
 6445        workspace: WeakEntity<Workspace>,
 6446        transaction: ProjectTransaction,
 6447        title: String,
 6448        cx: &mut AsyncWindowContext,
 6449    ) -> Result<()> {
 6450        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6451        cx.update(|_, cx| {
 6452            entries.sort_unstable_by_key(|(buffer, _)| {
 6453                buffer.read(cx).file().map(|f| f.path().clone())
 6454            });
 6455        })?;
 6456        if entries.is_empty() {
 6457            return Ok(());
 6458        }
 6459
 6460        // If the project transaction's edits are all contained within this editor, then
 6461        // avoid opening a new editor to display them.
 6462
 6463        if let [(buffer, transaction)] = &*entries {
 6464            let excerpt = editor.update(cx, |editor, cx| {
 6465                editor
 6466                    .buffer()
 6467                    .read(cx)
 6468                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6469            })?;
 6470            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6471                && excerpted_buffer == *buffer
 6472            {
 6473                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6474                    let excerpt_range = excerpt_range.to_offset(buffer);
 6475                    buffer
 6476                        .edited_ranges_for_transaction::<usize>(transaction)
 6477                        .all(|range| {
 6478                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6479                        })
 6480                })?;
 6481
 6482                if all_edits_within_excerpt {
 6483                    return Ok(());
 6484                }
 6485            }
 6486        }
 6487
 6488        let mut ranges_to_highlight = Vec::new();
 6489        let excerpt_buffer = cx.new(|cx| {
 6490            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6491            for (buffer_handle, transaction) in &entries {
 6492                let edited_ranges = buffer_handle
 6493                    .read(cx)
 6494                    .edited_ranges_for_transaction::<Point>(transaction)
 6495                    .collect::<Vec<_>>();
 6496                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6497                    PathKey::for_buffer(buffer_handle, cx),
 6498                    buffer_handle.clone(),
 6499                    edited_ranges,
 6500                    multibuffer_context_lines(cx),
 6501                    cx,
 6502                );
 6503
 6504                ranges_to_highlight.extend(ranges);
 6505            }
 6506            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6507            multibuffer
 6508        })?;
 6509
 6510        workspace.update_in(cx, |workspace, window, cx| {
 6511            let project = workspace.project().clone();
 6512            let editor =
 6513                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6514            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6515            editor.update(cx, |editor, cx| {
 6516                editor.highlight_background::<Self>(
 6517                    &ranges_to_highlight,
 6518                    |theme| theme.colors().editor_highlighted_line_background,
 6519                    cx,
 6520                );
 6521            });
 6522        })?;
 6523
 6524        Ok(())
 6525    }
 6526
 6527    pub fn clear_code_action_providers(&mut self) {
 6528        self.code_action_providers.clear();
 6529        self.available_code_actions.take();
 6530    }
 6531
 6532    pub fn add_code_action_provider(
 6533        &mut self,
 6534        provider: Rc<dyn CodeActionProvider>,
 6535        window: &mut Window,
 6536        cx: &mut Context<Self>,
 6537    ) {
 6538        if self
 6539            .code_action_providers
 6540            .iter()
 6541            .any(|existing_provider| existing_provider.id() == provider.id())
 6542        {
 6543            return;
 6544        }
 6545
 6546        self.code_action_providers.push(provider);
 6547        self.refresh_code_actions(window, cx);
 6548    }
 6549
 6550    pub fn remove_code_action_provider(
 6551        &mut self,
 6552        id: Arc<str>,
 6553        window: &mut Window,
 6554        cx: &mut Context<Self>,
 6555    ) {
 6556        self.code_action_providers
 6557            .retain(|provider| provider.id() != id);
 6558        self.refresh_code_actions(window, cx);
 6559    }
 6560
 6561    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6562        !self.code_action_providers.is_empty()
 6563            && EditorSettings::get_global(cx).toolbar.code_actions
 6564    }
 6565
 6566    pub fn has_available_code_actions(&self) -> bool {
 6567        self.available_code_actions
 6568            .as_ref()
 6569            .is_some_and(|(_, actions)| !actions.is_empty())
 6570    }
 6571
 6572    fn render_inline_code_actions(
 6573        &self,
 6574        icon_size: ui::IconSize,
 6575        display_row: DisplayRow,
 6576        is_active: bool,
 6577        cx: &mut Context<Self>,
 6578    ) -> AnyElement {
 6579        let show_tooltip = !self.context_menu_visible();
 6580        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6581            .icon_size(icon_size)
 6582            .shape(ui::IconButtonShape::Square)
 6583            .icon_color(ui::Color::Hidden)
 6584            .toggle_state(is_active)
 6585            .when(show_tooltip, |this| {
 6586                this.tooltip({
 6587                    let focus_handle = self.focus_handle.clone();
 6588                    move |window, cx| {
 6589                        Tooltip::for_action_in(
 6590                            "Toggle Code Actions",
 6591                            &ToggleCodeActions {
 6592                                deployed_from: None,
 6593                                quick_launch: false,
 6594                            },
 6595                            &focus_handle,
 6596                            window,
 6597                            cx,
 6598                        )
 6599                    }
 6600                })
 6601            })
 6602            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6603                window.focus(&editor.focus_handle(cx));
 6604                editor.toggle_code_actions(
 6605                    &crate::actions::ToggleCodeActions {
 6606                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6607                            display_row,
 6608                        )),
 6609                        quick_launch: false,
 6610                    },
 6611                    window,
 6612                    cx,
 6613                );
 6614            }))
 6615            .into_any_element()
 6616    }
 6617
 6618    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6619        &self.context_menu
 6620    }
 6621
 6622    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6623        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6624            cx.background_executor()
 6625                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6626                .await;
 6627
 6628            let (start_buffer, start, _, end, newest_selection) = this
 6629                .update(cx, |this, cx| {
 6630                    let newest_selection = this.selections.newest_anchor().clone();
 6631                    if newest_selection.head().diff_base_anchor.is_some() {
 6632                        return None;
 6633                    }
 6634                    let newest_selection_adjusted = this.selections.newest_adjusted(cx);
 6635                    let buffer = this.buffer.read(cx);
 6636
 6637                    let (start_buffer, start) =
 6638                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6639                    let (end_buffer, end) =
 6640                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6641
 6642                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6643                })?
 6644                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6645                .context(
 6646                    "Expected selection to lie in a single buffer when refreshing code actions",
 6647                )?;
 6648            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6649                let providers = this.code_action_providers.clone();
 6650                let tasks = this
 6651                    .code_action_providers
 6652                    .iter()
 6653                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6654                    .collect::<Vec<_>>();
 6655                (providers, tasks)
 6656            })?;
 6657
 6658            let mut actions = Vec::new();
 6659            for (provider, provider_actions) in
 6660                providers.into_iter().zip(future::join_all(tasks).await)
 6661            {
 6662                if let Some(provider_actions) = provider_actions.log_err() {
 6663                    actions.extend(provider_actions.into_iter().map(|action| {
 6664                        AvailableCodeAction {
 6665                            excerpt_id: newest_selection.start.excerpt_id,
 6666                            action,
 6667                            provider: provider.clone(),
 6668                        }
 6669                    }));
 6670                }
 6671            }
 6672
 6673            this.update(cx, |this, cx| {
 6674                this.available_code_actions = if actions.is_empty() {
 6675                    None
 6676                } else {
 6677                    Some((
 6678                        Location {
 6679                            buffer: start_buffer,
 6680                            range: start..end,
 6681                        },
 6682                        actions.into(),
 6683                    ))
 6684                };
 6685                cx.notify();
 6686            })
 6687        }));
 6688    }
 6689
 6690    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6691        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6692            self.show_git_blame_inline = false;
 6693
 6694            self.show_git_blame_inline_delay_task =
 6695                Some(cx.spawn_in(window, async move |this, cx| {
 6696                    cx.background_executor().timer(delay).await;
 6697
 6698                    this.update(cx, |this, cx| {
 6699                        this.show_git_blame_inline = true;
 6700                        cx.notify();
 6701                    })
 6702                    .log_err();
 6703                }));
 6704        }
 6705    }
 6706
 6707    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6708        let snapshot = self.snapshot(window, cx);
 6709        let cursor = self.selections.newest::<Point>(cx).head();
 6710        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6711        else {
 6712            return;
 6713        };
 6714
 6715        let Some(blame) = self.blame.as_ref() else {
 6716            return;
 6717        };
 6718
 6719        let row_info = RowInfo {
 6720            buffer_id: Some(buffer.remote_id()),
 6721            buffer_row: Some(point.row),
 6722            ..Default::default()
 6723        };
 6724        let Some((buffer, blame_entry)) = blame
 6725            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6726            .flatten()
 6727        else {
 6728            return;
 6729        };
 6730
 6731        let anchor = self.selections.newest_anchor().head();
 6732        let position = self.to_pixel_point(anchor, &snapshot, window);
 6733        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6734            self.show_blame_popover(
 6735                buffer,
 6736                &blame_entry,
 6737                position + last_bounds.origin,
 6738                true,
 6739                cx,
 6740            );
 6741        };
 6742    }
 6743
 6744    fn show_blame_popover(
 6745        &mut self,
 6746        buffer: BufferId,
 6747        blame_entry: &BlameEntry,
 6748        position: gpui::Point<Pixels>,
 6749        ignore_timeout: bool,
 6750        cx: &mut Context<Self>,
 6751    ) {
 6752        if let Some(state) = &mut self.inline_blame_popover {
 6753            state.hide_task.take();
 6754        } else {
 6755            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6756            let blame_entry = blame_entry.clone();
 6757            let show_task = cx.spawn(async move |editor, cx| {
 6758                if !ignore_timeout {
 6759                    cx.background_executor()
 6760                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6761                        .await;
 6762                }
 6763                editor
 6764                    .update(cx, |editor, cx| {
 6765                        editor.inline_blame_popover_show_task.take();
 6766                        let Some(blame) = editor.blame.as_ref() else {
 6767                            return;
 6768                        };
 6769                        let blame = blame.read(cx);
 6770                        let details = blame.details_for_entry(buffer, &blame_entry);
 6771                        let markdown = cx.new(|cx| {
 6772                            Markdown::new(
 6773                                details
 6774                                    .as_ref()
 6775                                    .map(|message| message.message.clone())
 6776                                    .unwrap_or_default(),
 6777                                None,
 6778                                None,
 6779                                cx,
 6780                            )
 6781                        });
 6782                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6783                            position,
 6784                            hide_task: None,
 6785                            popover_bounds: None,
 6786                            popover_state: InlineBlamePopoverState {
 6787                                scroll_handle: ScrollHandle::new(),
 6788                                commit_message: details,
 6789                                markdown,
 6790                            },
 6791                            keyboard_grace: ignore_timeout,
 6792                        });
 6793                        cx.notify();
 6794                    })
 6795                    .ok();
 6796            });
 6797            self.inline_blame_popover_show_task = Some(show_task);
 6798        }
 6799    }
 6800
 6801    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6802        self.inline_blame_popover_show_task.take();
 6803        if let Some(state) = &mut self.inline_blame_popover {
 6804            let hide_task = cx.spawn(async move |editor, cx| {
 6805                cx.background_executor()
 6806                    .timer(std::time::Duration::from_millis(100))
 6807                    .await;
 6808                editor
 6809                    .update(cx, |editor, cx| {
 6810                        editor.inline_blame_popover.take();
 6811                        cx.notify();
 6812                    })
 6813                    .ok();
 6814            });
 6815            state.hide_task = Some(hide_task);
 6816        }
 6817    }
 6818
 6819    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6820        if self.pending_rename.is_some() {
 6821            return None;
 6822        }
 6823
 6824        let provider = self.semantics_provider.clone()?;
 6825        let buffer = self.buffer.read(cx);
 6826        let newest_selection = self.selections.newest_anchor().clone();
 6827        let cursor_position = newest_selection.head();
 6828        let (cursor_buffer, cursor_buffer_position) =
 6829            buffer.text_anchor_for_position(cursor_position, cx)?;
 6830        let (tail_buffer, tail_buffer_position) =
 6831            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6832        if cursor_buffer != tail_buffer {
 6833            return None;
 6834        }
 6835
 6836        let snapshot = cursor_buffer.read(cx).snapshot();
 6837        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6838        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6839        if start_word_range != end_word_range {
 6840            self.document_highlights_task.take();
 6841            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6842            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6843            return None;
 6844        }
 6845
 6846        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6847        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6848            cx.background_executor()
 6849                .timer(Duration::from_millis(debounce))
 6850                .await;
 6851
 6852            let highlights = if let Some(highlights) = cx
 6853                .update(|cx| {
 6854                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6855                })
 6856                .ok()
 6857                .flatten()
 6858            {
 6859                highlights.await.log_err()
 6860            } else {
 6861                None
 6862            };
 6863
 6864            if let Some(highlights) = highlights {
 6865                this.update(cx, |this, cx| {
 6866                    if this.pending_rename.is_some() {
 6867                        return;
 6868                    }
 6869
 6870                    let buffer = this.buffer.read(cx);
 6871                    if buffer
 6872                        .text_anchor_for_position(cursor_position, cx)
 6873                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6874                    {
 6875                        return;
 6876                    }
 6877
 6878                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6879                    let mut write_ranges = Vec::new();
 6880                    let mut read_ranges = Vec::new();
 6881                    for highlight in highlights {
 6882                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6883                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6884                        {
 6885                            let start = highlight
 6886                                .range
 6887                                .start
 6888                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6889                            let end = highlight
 6890                                .range
 6891                                .end
 6892                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6893                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6894                                continue;
 6895                            }
 6896
 6897                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6898                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6899                                write_ranges.push(range);
 6900                            } else {
 6901                                read_ranges.push(range);
 6902                            }
 6903                        }
 6904                    }
 6905
 6906                    this.highlight_background::<DocumentHighlightRead>(
 6907                        &read_ranges,
 6908                        |theme| theme.colors().editor_document_highlight_read_background,
 6909                        cx,
 6910                    );
 6911                    this.highlight_background::<DocumentHighlightWrite>(
 6912                        &write_ranges,
 6913                        |theme| theme.colors().editor_document_highlight_write_background,
 6914                        cx,
 6915                    );
 6916                    cx.notify();
 6917                })
 6918                .log_err();
 6919            }
 6920        }));
 6921        None
 6922    }
 6923
 6924    fn prepare_highlight_query_from_selection(
 6925        &mut self,
 6926        cx: &mut Context<Editor>,
 6927    ) -> Option<(String, Range<Anchor>)> {
 6928        if matches!(self.mode, EditorMode::SingleLine) {
 6929            return None;
 6930        }
 6931        if !EditorSettings::get_global(cx).selection_highlight {
 6932            return None;
 6933        }
 6934        if self.selections.count() != 1 || self.selections.line_mode() {
 6935            return None;
 6936        }
 6937        let selection = self.selections.newest_anchor();
 6938        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6939        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6940            ..selection.end.to_point(&multi_buffer_snapshot);
 6941        // If the selection spans multiple rows OR it is empty
 6942        if selection_point_range.start.row != selection_point_range.end.row
 6943            || selection_point_range.start.column == selection_point_range.end.column
 6944        {
 6945            return None;
 6946        }
 6947
 6948        let query = multi_buffer_snapshot
 6949            .text_for_range(selection.range())
 6950            .collect::<String>();
 6951        if query.trim().is_empty() {
 6952            return None;
 6953        }
 6954        Some((query, selection.range()))
 6955    }
 6956
 6957    fn update_selection_occurrence_highlights(
 6958        &mut self,
 6959        query_text: String,
 6960        query_range: Range<Anchor>,
 6961        multi_buffer_range_to_query: Range<Point>,
 6962        use_debounce: bool,
 6963        window: &mut Window,
 6964        cx: &mut Context<Editor>,
 6965    ) -> Task<()> {
 6966        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6967        cx.spawn_in(window, async move |editor, cx| {
 6968            if use_debounce {
 6969                cx.background_executor()
 6970                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6971                    .await;
 6972            }
 6973            let match_task = cx.background_spawn(async move {
 6974                let buffer_ranges = multi_buffer_snapshot
 6975                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6976                    .into_iter()
 6977                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6978                let mut match_ranges = Vec::new();
 6979                let Ok(regex) = project::search::SearchQuery::text(
 6980                    query_text.clone(),
 6981                    false,
 6982                    false,
 6983                    false,
 6984                    Default::default(),
 6985                    Default::default(),
 6986                    false,
 6987                    None,
 6988                ) else {
 6989                    return Vec::default();
 6990                };
 6991                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6992                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6993                    match_ranges.extend(
 6994                        regex
 6995                            .search(buffer_snapshot, Some(search_range.clone()))
 6996                            .await
 6997                            .into_iter()
 6998                            .filter_map(|match_range| {
 6999                                let match_start = buffer_snapshot
 7000                                    .anchor_after(search_range.start + match_range.start);
 7001                                let match_end = buffer_snapshot
 7002                                    .anchor_before(search_range.start + match_range.end);
 7003                                let match_anchor_range = Anchor::range_in_buffer(
 7004                                    excerpt_id,
 7005                                    buffer_snapshot.remote_id(),
 7006                                    match_start..match_end,
 7007                                );
 7008                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7009                            }),
 7010                    );
 7011                }
 7012                match_ranges
 7013            });
 7014            let match_ranges = match_task.await;
 7015            editor
 7016                .update_in(cx, |editor, _, cx| {
 7017                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7018                    if !match_ranges.is_empty() {
 7019                        editor.highlight_background::<SelectedTextHighlight>(
 7020                            &match_ranges,
 7021                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7022                            cx,
 7023                        )
 7024                    }
 7025                })
 7026                .log_err();
 7027        })
 7028    }
 7029
 7030    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7031        struct NewlineFold;
 7032        let type_id = std::any::TypeId::of::<NewlineFold>();
 7033        if !self.mode.is_single_line() {
 7034            return;
 7035        }
 7036        let snapshot = self.snapshot(window, cx);
 7037        if snapshot.buffer_snapshot().max_point().row == 0 {
 7038            return;
 7039        }
 7040        let task = cx.background_spawn(async move {
 7041            let new_newlines = snapshot
 7042                .buffer_chars_at(0)
 7043                .filter_map(|(c, i)| {
 7044                    if c == '\n' {
 7045                        Some(
 7046                            snapshot.buffer_snapshot().anchor_after(i)
 7047                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7048                        )
 7049                    } else {
 7050                        None
 7051                    }
 7052                })
 7053                .collect::<Vec<_>>();
 7054            let existing_newlines = snapshot
 7055                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7056                .filter_map(|fold| {
 7057                    if fold.placeholder.type_tag == Some(type_id) {
 7058                        Some(fold.range.start..fold.range.end)
 7059                    } else {
 7060                        None
 7061                    }
 7062                })
 7063                .collect::<Vec<_>>();
 7064
 7065            (new_newlines, existing_newlines)
 7066        });
 7067        self.folding_newlines = cx.spawn(async move |this, cx| {
 7068            let (new_newlines, existing_newlines) = task.await;
 7069            if new_newlines == existing_newlines {
 7070                return;
 7071            }
 7072            let placeholder = FoldPlaceholder {
 7073                render: Arc::new(move |_, _, cx| {
 7074                    div()
 7075                        .bg(cx.theme().status().hint_background)
 7076                        .border_b_1()
 7077                        .size_full()
 7078                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7079                        .border_color(cx.theme().status().hint)
 7080                        .child("\\n")
 7081                        .into_any()
 7082                }),
 7083                constrain_width: false,
 7084                merge_adjacent: false,
 7085                type_tag: Some(type_id),
 7086            };
 7087            let creases = new_newlines
 7088                .into_iter()
 7089                .map(|range| Crease::simple(range, placeholder.clone()))
 7090                .collect();
 7091            this.update(cx, |this, cx| {
 7092                this.display_map.update(cx, |display_map, cx| {
 7093                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7094                    display_map.fold(creases, cx);
 7095                });
 7096            })
 7097            .ok();
 7098        });
 7099    }
 7100
 7101    fn refresh_selected_text_highlights(
 7102        &mut self,
 7103        on_buffer_edit: bool,
 7104        window: &mut Window,
 7105        cx: &mut Context<Editor>,
 7106    ) {
 7107        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7108        else {
 7109            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7110            self.quick_selection_highlight_task.take();
 7111            self.debounced_selection_highlight_task.take();
 7112            return;
 7113        };
 7114        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7115        if on_buffer_edit
 7116            || self
 7117                .quick_selection_highlight_task
 7118                .as_ref()
 7119                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7120        {
 7121            let multi_buffer_visible_start = self
 7122                .scroll_manager
 7123                .anchor()
 7124                .anchor
 7125                .to_point(&multi_buffer_snapshot);
 7126            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7127                multi_buffer_visible_start
 7128                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7129                Bias::Left,
 7130            );
 7131            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7132            self.quick_selection_highlight_task = Some((
 7133                query_range.clone(),
 7134                self.update_selection_occurrence_highlights(
 7135                    query_text.clone(),
 7136                    query_range.clone(),
 7137                    multi_buffer_visible_range,
 7138                    false,
 7139                    window,
 7140                    cx,
 7141                ),
 7142            ));
 7143        }
 7144        if on_buffer_edit
 7145            || self
 7146                .debounced_selection_highlight_task
 7147                .as_ref()
 7148                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7149        {
 7150            let multi_buffer_start = multi_buffer_snapshot
 7151                .anchor_before(0)
 7152                .to_point(&multi_buffer_snapshot);
 7153            let multi_buffer_end = multi_buffer_snapshot
 7154                .anchor_after(multi_buffer_snapshot.len())
 7155                .to_point(&multi_buffer_snapshot);
 7156            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7157            self.debounced_selection_highlight_task = Some((
 7158                query_range.clone(),
 7159                self.update_selection_occurrence_highlights(
 7160                    query_text,
 7161                    query_range,
 7162                    multi_buffer_full_range,
 7163                    true,
 7164                    window,
 7165                    cx,
 7166                ),
 7167            ));
 7168        }
 7169    }
 7170
 7171    pub fn refresh_edit_prediction(
 7172        &mut self,
 7173        debounce: bool,
 7174        user_requested: bool,
 7175        window: &mut Window,
 7176        cx: &mut Context<Self>,
 7177    ) -> Option<()> {
 7178        if DisableAiSettings::get_global(cx).disable_ai {
 7179            return None;
 7180        }
 7181
 7182        let provider = self.edit_prediction_provider()?;
 7183        let cursor = self.selections.newest_anchor().head();
 7184        let (buffer, cursor_buffer_position) =
 7185            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7186
 7187        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7188            self.discard_edit_prediction(false, cx);
 7189            return None;
 7190        }
 7191
 7192        self.update_visible_edit_prediction(window, cx);
 7193
 7194        if !user_requested
 7195            && (!self.should_show_edit_predictions()
 7196                || !self.is_focused(window)
 7197                || buffer.read(cx).is_empty())
 7198        {
 7199            self.discard_edit_prediction(false, cx);
 7200            return None;
 7201        }
 7202
 7203        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7204        Some(())
 7205    }
 7206
 7207    fn show_edit_predictions_in_menu(&self) -> bool {
 7208        match self.edit_prediction_settings {
 7209            EditPredictionSettings::Disabled => false,
 7210            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7211        }
 7212    }
 7213
 7214    pub fn edit_predictions_enabled(&self) -> bool {
 7215        match self.edit_prediction_settings {
 7216            EditPredictionSettings::Disabled => false,
 7217            EditPredictionSettings::Enabled { .. } => true,
 7218        }
 7219    }
 7220
 7221    fn edit_prediction_requires_modifier(&self) -> bool {
 7222        match self.edit_prediction_settings {
 7223            EditPredictionSettings::Disabled => false,
 7224            EditPredictionSettings::Enabled {
 7225                preview_requires_modifier,
 7226                ..
 7227            } => preview_requires_modifier,
 7228        }
 7229    }
 7230
 7231    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7232        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7233            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7234            self.discard_edit_prediction(false, cx);
 7235        } else {
 7236            let selection = self.selections.newest_anchor();
 7237            let cursor = selection.head();
 7238
 7239            if let Some((buffer, cursor_buffer_position)) =
 7240                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7241            {
 7242                self.edit_prediction_settings =
 7243                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7244            }
 7245        }
 7246    }
 7247
 7248    fn edit_prediction_settings_at_position(
 7249        &self,
 7250        buffer: &Entity<Buffer>,
 7251        buffer_position: language::Anchor,
 7252        cx: &App,
 7253    ) -> EditPredictionSettings {
 7254        if !self.mode.is_full()
 7255            || !self.show_edit_predictions_override.unwrap_or(true)
 7256            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7257        {
 7258            return EditPredictionSettings::Disabled;
 7259        }
 7260
 7261        let buffer = buffer.read(cx);
 7262
 7263        let file = buffer.file();
 7264
 7265        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7266            return EditPredictionSettings::Disabled;
 7267        };
 7268
 7269        let by_provider = matches!(
 7270            self.menu_edit_predictions_policy,
 7271            MenuEditPredictionsPolicy::ByProvider
 7272        );
 7273
 7274        let show_in_menu = by_provider
 7275            && self
 7276                .edit_prediction_provider
 7277                .as_ref()
 7278                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7279
 7280        let preview_requires_modifier =
 7281            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7282
 7283        EditPredictionSettings::Enabled {
 7284            show_in_menu,
 7285            preview_requires_modifier,
 7286        }
 7287    }
 7288
 7289    fn should_show_edit_predictions(&self) -> bool {
 7290        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7291    }
 7292
 7293    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7294        matches!(
 7295            self.edit_prediction_preview,
 7296            EditPredictionPreview::Active { .. }
 7297        )
 7298    }
 7299
 7300    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7301        let cursor = self.selections.newest_anchor().head();
 7302        if let Some((buffer, cursor_position)) =
 7303            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7304        {
 7305            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7306        } else {
 7307            false
 7308        }
 7309    }
 7310
 7311    pub fn supports_minimap(&self, cx: &App) -> bool {
 7312        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7313    }
 7314
 7315    fn edit_predictions_enabled_in_buffer(
 7316        &self,
 7317        buffer: &Entity<Buffer>,
 7318        buffer_position: language::Anchor,
 7319        cx: &App,
 7320    ) -> bool {
 7321        maybe!({
 7322            if self.read_only(cx) {
 7323                return Some(false);
 7324            }
 7325            let provider = self.edit_prediction_provider()?;
 7326            if !provider.is_enabled(buffer, buffer_position, cx) {
 7327                return Some(false);
 7328            }
 7329            let buffer = buffer.read(cx);
 7330            let Some(file) = buffer.file() else {
 7331                return Some(true);
 7332            };
 7333            let settings = all_language_settings(Some(file), cx);
 7334            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7335        })
 7336        .unwrap_or(false)
 7337    }
 7338
 7339    fn cycle_edit_prediction(
 7340        &mut self,
 7341        direction: Direction,
 7342        window: &mut Window,
 7343        cx: &mut Context<Self>,
 7344    ) -> Option<()> {
 7345        let provider = self.edit_prediction_provider()?;
 7346        let cursor = self.selections.newest_anchor().head();
 7347        let (buffer, cursor_buffer_position) =
 7348            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7349        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7350            return None;
 7351        }
 7352
 7353        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7354        self.update_visible_edit_prediction(window, cx);
 7355
 7356        Some(())
 7357    }
 7358
 7359    pub fn show_edit_prediction(
 7360        &mut self,
 7361        _: &ShowEditPrediction,
 7362        window: &mut Window,
 7363        cx: &mut Context<Self>,
 7364    ) {
 7365        if !self.has_active_edit_prediction() {
 7366            self.refresh_edit_prediction(false, true, window, cx);
 7367            return;
 7368        }
 7369
 7370        self.update_visible_edit_prediction(window, cx);
 7371    }
 7372
 7373    pub fn display_cursor_names(
 7374        &mut self,
 7375        _: &DisplayCursorNames,
 7376        window: &mut Window,
 7377        cx: &mut Context<Self>,
 7378    ) {
 7379        self.show_cursor_names(window, cx);
 7380    }
 7381
 7382    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7383        self.show_cursor_names = true;
 7384        cx.notify();
 7385        cx.spawn_in(window, async move |this, cx| {
 7386            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7387            this.update(cx, |this, cx| {
 7388                this.show_cursor_names = false;
 7389                cx.notify()
 7390            })
 7391            .ok()
 7392        })
 7393        .detach();
 7394    }
 7395
 7396    pub fn next_edit_prediction(
 7397        &mut self,
 7398        _: &NextEditPrediction,
 7399        window: &mut Window,
 7400        cx: &mut Context<Self>,
 7401    ) {
 7402        if self.has_active_edit_prediction() {
 7403            self.cycle_edit_prediction(Direction::Next, window, cx);
 7404        } else {
 7405            let is_copilot_disabled = self
 7406                .refresh_edit_prediction(false, true, window, cx)
 7407                .is_none();
 7408            if is_copilot_disabled {
 7409                cx.propagate();
 7410            }
 7411        }
 7412    }
 7413
 7414    pub fn previous_edit_prediction(
 7415        &mut self,
 7416        _: &PreviousEditPrediction,
 7417        window: &mut Window,
 7418        cx: &mut Context<Self>,
 7419    ) {
 7420        if self.has_active_edit_prediction() {
 7421            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7422        } else {
 7423            let is_copilot_disabled = self
 7424                .refresh_edit_prediction(false, true, window, cx)
 7425                .is_none();
 7426            if is_copilot_disabled {
 7427                cx.propagate();
 7428            }
 7429        }
 7430    }
 7431
 7432    pub fn accept_edit_prediction(
 7433        &mut self,
 7434        _: &AcceptEditPrediction,
 7435        window: &mut Window,
 7436        cx: &mut Context<Self>,
 7437    ) {
 7438        if self.show_edit_predictions_in_menu() {
 7439            self.hide_context_menu(window, cx);
 7440        }
 7441
 7442        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7443            return;
 7444        };
 7445
 7446        match &active_edit_prediction.completion {
 7447            EditPrediction::MoveWithin { target, .. } => {
 7448                let target = *target;
 7449
 7450                if let Some(position_map) = &self.last_position_map {
 7451                    if position_map
 7452                        .visible_row_range
 7453                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7454                        || !self.edit_prediction_requires_modifier()
 7455                    {
 7456                        self.unfold_ranges(&[target..target], true, false, cx);
 7457                        // Note that this is also done in vim's handler of the Tab action.
 7458                        self.change_selections(
 7459                            SelectionEffects::scroll(Autoscroll::newest()),
 7460                            window,
 7461                            cx,
 7462                            |selections| {
 7463                                selections.select_anchor_ranges([target..target]);
 7464                            },
 7465                        );
 7466                        self.clear_row_highlights::<EditPredictionPreview>();
 7467
 7468                        self.edit_prediction_preview
 7469                            .set_previous_scroll_position(None);
 7470                    } else {
 7471                        self.edit_prediction_preview
 7472                            .set_previous_scroll_position(Some(
 7473                                position_map.snapshot.scroll_anchor,
 7474                            ));
 7475
 7476                        self.highlight_rows::<EditPredictionPreview>(
 7477                            target..target,
 7478                            cx.theme().colors().editor_highlighted_line_background,
 7479                            RowHighlightOptions {
 7480                                autoscroll: true,
 7481                                ..Default::default()
 7482                            },
 7483                            cx,
 7484                        );
 7485                        self.request_autoscroll(Autoscroll::fit(), cx);
 7486                    }
 7487                }
 7488            }
 7489            EditPrediction::MoveOutside { snapshot, target } => {
 7490                if let Some(workspace) = self.workspace() {
 7491                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7492                        .detach_and_log_err(cx);
 7493                }
 7494            }
 7495            EditPrediction::Edit { edits, .. } => {
 7496                self.report_edit_prediction_event(
 7497                    active_edit_prediction.completion_id.clone(),
 7498                    true,
 7499                    cx,
 7500                );
 7501
 7502                if let Some(provider) = self.edit_prediction_provider() {
 7503                    provider.accept(cx);
 7504                }
 7505
 7506                // Store the transaction ID and selections before applying the edit
 7507                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7508
 7509                let snapshot = self.buffer.read(cx).snapshot(cx);
 7510                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7511
 7512                self.buffer.update(cx, |buffer, cx| {
 7513                    buffer.edit(edits.iter().cloned(), None, cx)
 7514                });
 7515
 7516                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7517                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7518                });
 7519
 7520                let selections = self.selections.disjoint_anchors_arc();
 7521                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7522                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7523                    if has_new_transaction {
 7524                        self.selection_history
 7525                            .insert_transaction(transaction_id_now, selections);
 7526                    }
 7527                }
 7528
 7529                self.update_visible_edit_prediction(window, cx);
 7530                if self.active_edit_prediction.is_none() {
 7531                    self.refresh_edit_prediction(true, true, window, cx);
 7532                }
 7533
 7534                cx.notify();
 7535            }
 7536        }
 7537
 7538        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7539    }
 7540
 7541    pub fn accept_partial_edit_prediction(
 7542        &mut self,
 7543        _: &AcceptPartialEditPrediction,
 7544        window: &mut Window,
 7545        cx: &mut Context<Self>,
 7546    ) {
 7547        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7548            return;
 7549        };
 7550        if self.selections.count() != 1 {
 7551            return;
 7552        }
 7553
 7554        match &active_edit_prediction.completion {
 7555            EditPrediction::MoveWithin { target, .. } => {
 7556                let target = *target;
 7557                self.change_selections(
 7558                    SelectionEffects::scroll(Autoscroll::newest()),
 7559                    window,
 7560                    cx,
 7561                    |selections| {
 7562                        selections.select_anchor_ranges([target..target]);
 7563                    },
 7564                );
 7565            }
 7566            EditPrediction::MoveOutside { snapshot, target } => {
 7567                if let Some(workspace) = self.workspace() {
 7568                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7569                        .detach_and_log_err(cx);
 7570                }
 7571            }
 7572            EditPrediction::Edit { edits, .. } => {
 7573                self.report_edit_prediction_event(
 7574                    active_edit_prediction.completion_id.clone(),
 7575                    true,
 7576                    cx,
 7577                );
 7578
 7579                // Find an insertion that starts at the cursor position.
 7580                let snapshot = self.buffer.read(cx).snapshot(cx);
 7581                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7582                let insertion = edits.iter().find_map(|(range, text)| {
 7583                    let range = range.to_offset(&snapshot);
 7584                    if range.is_empty() && range.start == cursor_offset {
 7585                        Some(text)
 7586                    } else {
 7587                        None
 7588                    }
 7589                });
 7590
 7591                if let Some(text) = insertion {
 7592                    let mut partial_completion = text
 7593                        .chars()
 7594                        .by_ref()
 7595                        .take_while(|c| c.is_alphabetic())
 7596                        .collect::<String>();
 7597                    if partial_completion.is_empty() {
 7598                        partial_completion = text
 7599                            .chars()
 7600                            .by_ref()
 7601                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7602                            .collect::<String>();
 7603                    }
 7604
 7605                    cx.emit(EditorEvent::InputHandled {
 7606                        utf16_range_to_replace: None,
 7607                        text: partial_completion.clone().into(),
 7608                    });
 7609
 7610                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7611
 7612                    self.refresh_edit_prediction(true, true, window, cx);
 7613                    cx.notify();
 7614                } else {
 7615                    self.accept_edit_prediction(&Default::default(), window, cx);
 7616                }
 7617            }
 7618        }
 7619    }
 7620
 7621    fn discard_edit_prediction(
 7622        &mut self,
 7623        should_report_edit_prediction_event: bool,
 7624        cx: &mut Context<Self>,
 7625    ) -> bool {
 7626        if should_report_edit_prediction_event {
 7627            let completion_id = self
 7628                .active_edit_prediction
 7629                .as_ref()
 7630                .and_then(|active_completion| active_completion.completion_id.clone());
 7631
 7632            self.report_edit_prediction_event(completion_id, false, cx);
 7633        }
 7634
 7635        if let Some(provider) = self.edit_prediction_provider() {
 7636            provider.discard(cx);
 7637        }
 7638
 7639        self.take_active_edit_prediction(cx)
 7640    }
 7641
 7642    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7643        let Some(provider) = self.edit_prediction_provider() else {
 7644            return;
 7645        };
 7646
 7647        let Some((_, buffer, _)) = self
 7648            .buffer
 7649            .read(cx)
 7650            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7651        else {
 7652            return;
 7653        };
 7654
 7655        let extension = buffer
 7656            .read(cx)
 7657            .file()
 7658            .and_then(|file| Some(file.path().extension()?.to_string()));
 7659
 7660        let event_type = match accepted {
 7661            true => "Edit Prediction Accepted",
 7662            false => "Edit Prediction Discarded",
 7663        };
 7664        telemetry::event!(
 7665            event_type,
 7666            provider = provider.name(),
 7667            prediction_id = id,
 7668            suggestion_accepted = accepted,
 7669            file_extension = extension,
 7670        );
 7671    }
 7672
 7673    fn open_editor_at_anchor(
 7674        snapshot: &language::BufferSnapshot,
 7675        target: language::Anchor,
 7676        workspace: &Entity<Workspace>,
 7677        window: &mut Window,
 7678        cx: &mut App,
 7679    ) -> Task<Result<()>> {
 7680        workspace.update(cx, |workspace, cx| {
 7681            let path = snapshot.file().map(|file| file.full_path(cx));
 7682            let Some(path) =
 7683                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7684            else {
 7685                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7686            };
 7687            let target = text::ToPoint::to_point(&target, snapshot);
 7688            let item = workspace.open_path(path, None, true, window, cx);
 7689            window.spawn(cx, async move |cx| {
 7690                let Some(editor) = item.await?.downcast::<Editor>() else {
 7691                    return Ok(());
 7692                };
 7693                editor
 7694                    .update_in(cx, |editor, window, cx| {
 7695                        editor.go_to_singleton_buffer_point(target, window, cx);
 7696                    })
 7697                    .ok();
 7698                anyhow::Ok(())
 7699            })
 7700        })
 7701    }
 7702
 7703    pub fn has_active_edit_prediction(&self) -> bool {
 7704        self.active_edit_prediction.is_some()
 7705    }
 7706
 7707    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7708        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7709            return false;
 7710        };
 7711
 7712        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7713        self.clear_highlights::<EditPredictionHighlight>(cx);
 7714        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7715        true
 7716    }
 7717
 7718    /// Returns true when we're displaying the edit prediction popover below the cursor
 7719    /// like we are not previewing and the LSP autocomplete menu is visible
 7720    /// or we are in `when_holding_modifier` mode.
 7721    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7722        if self.edit_prediction_preview_is_active()
 7723            || !self.show_edit_predictions_in_menu()
 7724            || !self.edit_predictions_enabled()
 7725        {
 7726            return false;
 7727        }
 7728
 7729        if self.has_visible_completions_menu() {
 7730            return true;
 7731        }
 7732
 7733        has_completion && self.edit_prediction_requires_modifier()
 7734    }
 7735
 7736    fn handle_modifiers_changed(
 7737        &mut self,
 7738        modifiers: Modifiers,
 7739        position_map: &PositionMap,
 7740        window: &mut Window,
 7741        cx: &mut Context<Self>,
 7742    ) {
 7743        if self.show_edit_predictions_in_menu() {
 7744            self.update_edit_prediction_preview(&modifiers, window, cx);
 7745        }
 7746
 7747        self.update_selection_mode(&modifiers, position_map, window, cx);
 7748
 7749        let mouse_position = window.mouse_position();
 7750        if !position_map.text_hitbox.is_hovered(window) {
 7751            return;
 7752        }
 7753
 7754        self.update_hovered_link(
 7755            position_map.point_for_position(mouse_position),
 7756            &position_map.snapshot,
 7757            modifiers,
 7758            window,
 7759            cx,
 7760        )
 7761    }
 7762
 7763    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7764        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7765        if invert {
 7766            match multi_cursor_setting {
 7767                MultiCursorModifier::Alt => modifiers.alt,
 7768                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7769            }
 7770        } else {
 7771            match multi_cursor_setting {
 7772                MultiCursorModifier::Alt => modifiers.secondary(),
 7773                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7774            }
 7775        }
 7776    }
 7777
 7778    fn columnar_selection_mode(
 7779        modifiers: &Modifiers,
 7780        cx: &mut Context<Self>,
 7781    ) -> Option<ColumnarMode> {
 7782        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7783            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7784                Some(ColumnarMode::FromMouse)
 7785            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7786                Some(ColumnarMode::FromSelection)
 7787            } else {
 7788                None
 7789            }
 7790        } else {
 7791            None
 7792        }
 7793    }
 7794
 7795    fn update_selection_mode(
 7796        &mut self,
 7797        modifiers: &Modifiers,
 7798        position_map: &PositionMap,
 7799        window: &mut Window,
 7800        cx: &mut Context<Self>,
 7801    ) {
 7802        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7803            return;
 7804        };
 7805        if self.selections.pending_anchor().is_none() {
 7806            return;
 7807        }
 7808
 7809        let mouse_position = window.mouse_position();
 7810        let point_for_position = position_map.point_for_position(mouse_position);
 7811        let position = point_for_position.previous_valid;
 7812
 7813        self.select(
 7814            SelectPhase::BeginColumnar {
 7815                position,
 7816                reset: false,
 7817                mode,
 7818                goal_column: point_for_position.exact_unclipped.column(),
 7819            },
 7820            window,
 7821            cx,
 7822        );
 7823    }
 7824
 7825    fn update_edit_prediction_preview(
 7826        &mut self,
 7827        modifiers: &Modifiers,
 7828        window: &mut Window,
 7829        cx: &mut Context<Self>,
 7830    ) {
 7831        let mut modifiers_held = false;
 7832        if let Some(accept_keystroke) = self
 7833            .accept_edit_prediction_keybind(false, window, cx)
 7834            .keystroke()
 7835        {
 7836            modifiers_held = modifiers_held
 7837                || (accept_keystroke.modifiers() == modifiers
 7838                    && accept_keystroke.modifiers().modified());
 7839        };
 7840        if let Some(accept_partial_keystroke) = self
 7841            .accept_edit_prediction_keybind(true, window, cx)
 7842            .keystroke()
 7843        {
 7844            modifiers_held = modifiers_held
 7845                || (accept_partial_keystroke.modifiers() == modifiers
 7846                    && accept_partial_keystroke.modifiers().modified());
 7847        }
 7848
 7849        if modifiers_held {
 7850            if matches!(
 7851                self.edit_prediction_preview,
 7852                EditPredictionPreview::Inactive { .. }
 7853            ) {
 7854                self.edit_prediction_preview = EditPredictionPreview::Active {
 7855                    previous_scroll_position: None,
 7856                    since: Instant::now(),
 7857                };
 7858
 7859                self.update_visible_edit_prediction(window, cx);
 7860                cx.notify();
 7861            }
 7862        } else if let EditPredictionPreview::Active {
 7863            previous_scroll_position,
 7864            since,
 7865        } = self.edit_prediction_preview
 7866        {
 7867            if let (Some(previous_scroll_position), Some(position_map)) =
 7868                (previous_scroll_position, self.last_position_map.as_ref())
 7869            {
 7870                self.set_scroll_position(
 7871                    previous_scroll_position
 7872                        .scroll_position(&position_map.snapshot.display_snapshot),
 7873                    window,
 7874                    cx,
 7875                );
 7876            }
 7877
 7878            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7879                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7880            };
 7881            self.clear_row_highlights::<EditPredictionPreview>();
 7882            self.update_visible_edit_prediction(window, cx);
 7883            cx.notify();
 7884        }
 7885    }
 7886
 7887    fn update_visible_edit_prediction(
 7888        &mut self,
 7889        _window: &mut Window,
 7890        cx: &mut Context<Self>,
 7891    ) -> Option<()> {
 7892        if DisableAiSettings::get_global(cx).disable_ai {
 7893            return None;
 7894        }
 7895
 7896        if self.ime_transaction.is_some() {
 7897            self.discard_edit_prediction(false, cx);
 7898            return None;
 7899        }
 7900
 7901        let selection = self.selections.newest_anchor();
 7902        let cursor = selection.head();
 7903        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7904        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7905        let excerpt_id = cursor.excerpt_id;
 7906
 7907        let show_in_menu = self.show_edit_predictions_in_menu();
 7908        let completions_menu_has_precedence = !show_in_menu
 7909            && (self.context_menu.borrow().is_some()
 7910                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7911
 7912        if completions_menu_has_precedence
 7913            || !offset_selection.is_empty()
 7914            || self
 7915                .active_edit_prediction
 7916                .as_ref()
 7917                .is_some_and(|completion| {
 7918                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7919                        return false;
 7920                    };
 7921                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7922                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7923                    !invalidation_range.contains(&offset_selection.head())
 7924                })
 7925        {
 7926            self.discard_edit_prediction(false, cx);
 7927            return None;
 7928        }
 7929
 7930        self.take_active_edit_prediction(cx);
 7931        let Some(provider) = self.edit_prediction_provider() else {
 7932            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7933            return None;
 7934        };
 7935
 7936        let (buffer, cursor_buffer_position) =
 7937            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7938
 7939        self.edit_prediction_settings =
 7940            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7941
 7942        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7943
 7944        if self.edit_prediction_indent_conflict {
 7945            let cursor_point = cursor.to_point(&multibuffer);
 7946
 7947            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7948
 7949            if let Some((_, indent)) = indents.iter().next()
 7950                && indent.len == cursor_point.column
 7951            {
 7952                self.edit_prediction_indent_conflict = false;
 7953            }
 7954        }
 7955
 7956        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7957
 7958        let (completion_id, edits, edit_preview) = match edit_prediction {
 7959            edit_prediction::EditPrediction::Local {
 7960                id,
 7961                edits,
 7962                edit_preview,
 7963            } => (id, edits, edit_preview),
 7964            edit_prediction::EditPrediction::Jump {
 7965                id,
 7966                snapshot,
 7967                target,
 7968            } => {
 7969                self.stale_edit_prediction_in_menu = None;
 7970                self.active_edit_prediction = Some(EditPredictionState {
 7971                    inlay_ids: vec![],
 7972                    completion: EditPrediction::MoveOutside { snapshot, target },
 7973                    completion_id: id,
 7974                    invalidation_range: None,
 7975                });
 7976                cx.notify();
 7977                return Some(());
 7978            }
 7979        };
 7980
 7981        let edits = edits
 7982            .into_iter()
 7983            .flat_map(|(range, new_text)| {
 7984                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7985                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7986                Some((start..end, new_text))
 7987            })
 7988            .collect::<Vec<_>>();
 7989        if edits.is_empty() {
 7990            return None;
 7991        }
 7992
 7993        let first_edit_start = edits.first().unwrap().0.start;
 7994        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7995        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7996
 7997        let last_edit_end = edits.last().unwrap().0.end;
 7998        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7999        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8000
 8001        let cursor_row = cursor.to_point(&multibuffer).row;
 8002
 8003        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8004
 8005        let mut inlay_ids = Vec::new();
 8006        let invalidation_row_range;
 8007        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8008            Some(cursor_row..edit_end_row)
 8009        } else if cursor_row > edit_end_row {
 8010            Some(edit_start_row..cursor_row)
 8011        } else {
 8012            None
 8013        };
 8014        let supports_jump = self
 8015            .edit_prediction_provider
 8016            .as_ref()
 8017            .map(|provider| provider.provider.supports_jump_to_edit())
 8018            .unwrap_or(true);
 8019
 8020        let is_move = supports_jump
 8021            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8022        let completion = if is_move {
 8023            invalidation_row_range =
 8024                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8025            let target = first_edit_start;
 8026            EditPrediction::MoveWithin { target, snapshot }
 8027        } else {
 8028            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8029                && !self.edit_predictions_hidden_for_vim_mode;
 8030
 8031            if show_completions_in_buffer {
 8032                if edits
 8033                    .iter()
 8034                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8035                {
 8036                    let mut inlays = Vec::new();
 8037                    for (range, new_text) in &edits {
 8038                        let inlay = Inlay::edit_prediction(
 8039                            post_inc(&mut self.next_inlay_id),
 8040                            range.start,
 8041                            new_text.as_str(),
 8042                        );
 8043                        inlay_ids.push(inlay.id);
 8044                        inlays.push(inlay);
 8045                    }
 8046
 8047                    self.splice_inlays(&[], inlays, cx);
 8048                } else {
 8049                    let background_color = cx.theme().status().deleted_background;
 8050                    self.highlight_text::<EditPredictionHighlight>(
 8051                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8052                        HighlightStyle {
 8053                            background_color: Some(background_color),
 8054                            ..Default::default()
 8055                        },
 8056                        cx,
 8057                    );
 8058                }
 8059            }
 8060
 8061            invalidation_row_range = edit_start_row..edit_end_row;
 8062
 8063            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8064                if provider.show_tab_accept_marker() {
 8065                    EditDisplayMode::TabAccept
 8066                } else {
 8067                    EditDisplayMode::Inline
 8068                }
 8069            } else {
 8070                EditDisplayMode::DiffPopover
 8071            };
 8072
 8073            EditPrediction::Edit {
 8074                edits,
 8075                edit_preview,
 8076                display_mode,
 8077                snapshot,
 8078            }
 8079        };
 8080
 8081        let invalidation_range = multibuffer
 8082            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8083            ..multibuffer.anchor_after(Point::new(
 8084                invalidation_row_range.end,
 8085                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8086            ));
 8087
 8088        self.stale_edit_prediction_in_menu = None;
 8089        self.active_edit_prediction = Some(EditPredictionState {
 8090            inlay_ids,
 8091            completion,
 8092            completion_id,
 8093            invalidation_range: Some(invalidation_range),
 8094        });
 8095
 8096        cx.notify();
 8097
 8098        Some(())
 8099    }
 8100
 8101    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8102        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8103    }
 8104
 8105    fn clear_tasks(&mut self) {
 8106        self.tasks.clear()
 8107    }
 8108
 8109    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8110        if self.tasks.insert(key, value).is_some() {
 8111            // This case should hopefully be rare, but just in case...
 8112            log::error!(
 8113                "multiple different run targets found on a single line, only the last target will be rendered"
 8114            )
 8115        }
 8116    }
 8117
 8118    /// Get all display points of breakpoints that will be rendered within editor
 8119    ///
 8120    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8121    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8122    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8123    fn active_breakpoints(
 8124        &self,
 8125        range: Range<DisplayRow>,
 8126        window: &mut Window,
 8127        cx: &mut Context<Self>,
 8128    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8129        let mut breakpoint_display_points = HashMap::default();
 8130
 8131        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8132            return breakpoint_display_points;
 8133        };
 8134
 8135        let snapshot = self.snapshot(window, cx);
 8136
 8137        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8138        let Some(project) = self.project() else {
 8139            return breakpoint_display_points;
 8140        };
 8141
 8142        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8143            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8144
 8145        for (buffer_snapshot, range, excerpt_id) in
 8146            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8147        {
 8148            let Some(buffer) = project
 8149                .read(cx)
 8150                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8151            else {
 8152                continue;
 8153            };
 8154            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8155                &buffer,
 8156                Some(
 8157                    buffer_snapshot.anchor_before(range.start)
 8158                        ..buffer_snapshot.anchor_after(range.end),
 8159                ),
 8160                buffer_snapshot,
 8161                cx,
 8162            );
 8163            for (breakpoint, state) in breakpoints {
 8164                let multi_buffer_anchor =
 8165                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8166                let position = multi_buffer_anchor
 8167                    .to_point(multi_buffer_snapshot)
 8168                    .to_display_point(&snapshot);
 8169
 8170                breakpoint_display_points.insert(
 8171                    position.row(),
 8172                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8173                );
 8174            }
 8175        }
 8176
 8177        breakpoint_display_points
 8178    }
 8179
 8180    fn breakpoint_context_menu(
 8181        &self,
 8182        anchor: Anchor,
 8183        window: &mut Window,
 8184        cx: &mut Context<Self>,
 8185    ) -> Entity<ui::ContextMenu> {
 8186        let weak_editor = cx.weak_entity();
 8187        let focus_handle = self.focus_handle(cx);
 8188
 8189        let row = self
 8190            .buffer
 8191            .read(cx)
 8192            .snapshot(cx)
 8193            .summary_for_anchor::<Point>(&anchor)
 8194            .row;
 8195
 8196        let breakpoint = self
 8197            .breakpoint_at_row(row, window, cx)
 8198            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8199
 8200        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8201            "Edit Log Breakpoint"
 8202        } else {
 8203            "Set Log Breakpoint"
 8204        };
 8205
 8206        let condition_breakpoint_msg = if breakpoint
 8207            .as_ref()
 8208            .is_some_and(|bp| bp.1.condition.is_some())
 8209        {
 8210            "Edit Condition Breakpoint"
 8211        } else {
 8212            "Set Condition Breakpoint"
 8213        };
 8214
 8215        let hit_condition_breakpoint_msg = if breakpoint
 8216            .as_ref()
 8217            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8218        {
 8219            "Edit Hit Condition Breakpoint"
 8220        } else {
 8221            "Set Hit Condition Breakpoint"
 8222        };
 8223
 8224        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8225            "Unset Breakpoint"
 8226        } else {
 8227            "Set Breakpoint"
 8228        };
 8229
 8230        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8231
 8232        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8233            BreakpointState::Enabled => Some("Disable"),
 8234            BreakpointState::Disabled => Some("Enable"),
 8235        });
 8236
 8237        let (anchor, breakpoint) =
 8238            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8239
 8240        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8241            menu.on_blur_subscription(Subscription::new(|| {}))
 8242                .context(focus_handle)
 8243                .when(run_to_cursor, |this| {
 8244                    let weak_editor = weak_editor.clone();
 8245                    this.entry("Run to cursor", None, move |window, cx| {
 8246                        weak_editor
 8247                            .update(cx, |editor, cx| {
 8248                                editor.change_selections(
 8249                                    SelectionEffects::no_scroll(),
 8250                                    window,
 8251                                    cx,
 8252                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8253                                );
 8254                            })
 8255                            .ok();
 8256
 8257                        window.dispatch_action(Box::new(RunToCursor), cx);
 8258                    })
 8259                    .separator()
 8260                })
 8261                .when_some(toggle_state_msg, |this, msg| {
 8262                    this.entry(msg, None, {
 8263                        let weak_editor = weak_editor.clone();
 8264                        let breakpoint = breakpoint.clone();
 8265                        move |_window, cx| {
 8266                            weak_editor
 8267                                .update(cx, |this, cx| {
 8268                                    this.edit_breakpoint_at_anchor(
 8269                                        anchor,
 8270                                        breakpoint.as_ref().clone(),
 8271                                        BreakpointEditAction::InvertState,
 8272                                        cx,
 8273                                    );
 8274                                })
 8275                                .log_err();
 8276                        }
 8277                    })
 8278                })
 8279                .entry(set_breakpoint_msg, None, {
 8280                    let weak_editor = weak_editor.clone();
 8281                    let breakpoint = breakpoint.clone();
 8282                    move |_window, cx| {
 8283                        weak_editor
 8284                            .update(cx, |this, cx| {
 8285                                this.edit_breakpoint_at_anchor(
 8286                                    anchor,
 8287                                    breakpoint.as_ref().clone(),
 8288                                    BreakpointEditAction::Toggle,
 8289                                    cx,
 8290                                );
 8291                            })
 8292                            .log_err();
 8293                    }
 8294                })
 8295                .entry(log_breakpoint_msg, None, {
 8296                    let breakpoint = breakpoint.clone();
 8297                    let weak_editor = weak_editor.clone();
 8298                    move |window, cx| {
 8299                        weak_editor
 8300                            .update(cx, |this, cx| {
 8301                                this.add_edit_breakpoint_block(
 8302                                    anchor,
 8303                                    breakpoint.as_ref(),
 8304                                    BreakpointPromptEditAction::Log,
 8305                                    window,
 8306                                    cx,
 8307                                );
 8308                            })
 8309                            .log_err();
 8310                    }
 8311                })
 8312                .entry(condition_breakpoint_msg, None, {
 8313                    let breakpoint = breakpoint.clone();
 8314                    let weak_editor = weak_editor.clone();
 8315                    move |window, cx| {
 8316                        weak_editor
 8317                            .update(cx, |this, cx| {
 8318                                this.add_edit_breakpoint_block(
 8319                                    anchor,
 8320                                    breakpoint.as_ref(),
 8321                                    BreakpointPromptEditAction::Condition,
 8322                                    window,
 8323                                    cx,
 8324                                );
 8325                            })
 8326                            .log_err();
 8327                    }
 8328                })
 8329                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8330                    weak_editor
 8331                        .update(cx, |this, cx| {
 8332                            this.add_edit_breakpoint_block(
 8333                                anchor,
 8334                                breakpoint.as_ref(),
 8335                                BreakpointPromptEditAction::HitCondition,
 8336                                window,
 8337                                cx,
 8338                            );
 8339                        })
 8340                        .log_err();
 8341                })
 8342        })
 8343    }
 8344
 8345    fn render_breakpoint(
 8346        &self,
 8347        position: Anchor,
 8348        row: DisplayRow,
 8349        breakpoint: &Breakpoint,
 8350        state: Option<BreakpointSessionState>,
 8351        cx: &mut Context<Self>,
 8352    ) -> IconButton {
 8353        let is_rejected = state.is_some_and(|s| !s.verified);
 8354        // Is it a breakpoint that shows up when hovering over gutter?
 8355        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8356            (false, false),
 8357            |PhantomBreakpointIndicator {
 8358                 is_active,
 8359                 display_row,
 8360                 collides_with_existing_breakpoint,
 8361             }| {
 8362                (
 8363                    is_active && display_row == row,
 8364                    collides_with_existing_breakpoint,
 8365                )
 8366            },
 8367        );
 8368
 8369        let (color, icon) = {
 8370            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8371                (false, false) => ui::IconName::DebugBreakpoint,
 8372                (true, false) => ui::IconName::DebugLogBreakpoint,
 8373                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8374                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8375            };
 8376
 8377            let color = if is_phantom {
 8378                Color::Hint
 8379            } else if is_rejected {
 8380                Color::Disabled
 8381            } else {
 8382                Color::Debugger
 8383            };
 8384
 8385            (color, icon)
 8386        };
 8387
 8388        let breakpoint = Arc::from(breakpoint.clone());
 8389
 8390        let alt_as_text = gpui::Keystroke {
 8391            modifiers: Modifiers::secondary_key(),
 8392            ..Default::default()
 8393        };
 8394        let primary_action_text = if breakpoint.is_disabled() {
 8395            "Enable breakpoint"
 8396        } else if is_phantom && !collides_with_existing {
 8397            "Set breakpoint"
 8398        } else {
 8399            "Unset breakpoint"
 8400        };
 8401        let focus_handle = self.focus_handle.clone();
 8402
 8403        let meta = if is_rejected {
 8404            SharedString::from("No executable code is associated with this line.")
 8405        } else if collides_with_existing && !breakpoint.is_disabled() {
 8406            SharedString::from(format!(
 8407                "{alt_as_text}-click to disable,\nright-click for more options."
 8408            ))
 8409        } else {
 8410            SharedString::from("Right-click for more options.")
 8411        };
 8412        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8413            .icon_size(IconSize::XSmall)
 8414            .size(ui::ButtonSize::None)
 8415            .when(is_rejected, |this| {
 8416                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8417            })
 8418            .icon_color(color)
 8419            .style(ButtonStyle::Transparent)
 8420            .on_click(cx.listener({
 8421                move |editor, event: &ClickEvent, window, cx| {
 8422                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8423                        BreakpointEditAction::InvertState
 8424                    } else {
 8425                        BreakpointEditAction::Toggle
 8426                    };
 8427
 8428                    window.focus(&editor.focus_handle(cx));
 8429                    editor.edit_breakpoint_at_anchor(
 8430                        position,
 8431                        breakpoint.as_ref().clone(),
 8432                        edit_action,
 8433                        cx,
 8434                    );
 8435                }
 8436            }))
 8437            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8438                editor.set_breakpoint_context_menu(
 8439                    row,
 8440                    Some(position),
 8441                    event.position(),
 8442                    window,
 8443                    cx,
 8444                );
 8445            }))
 8446            .tooltip(move |window, cx| {
 8447                Tooltip::with_meta_in(
 8448                    primary_action_text,
 8449                    Some(&ToggleBreakpoint),
 8450                    meta.clone(),
 8451                    &focus_handle,
 8452                    window,
 8453                    cx,
 8454                )
 8455            })
 8456    }
 8457
 8458    fn build_tasks_context(
 8459        project: &Entity<Project>,
 8460        buffer: &Entity<Buffer>,
 8461        buffer_row: u32,
 8462        tasks: &Arc<RunnableTasks>,
 8463        cx: &mut Context<Self>,
 8464    ) -> Task<Option<task::TaskContext>> {
 8465        let position = Point::new(buffer_row, tasks.column);
 8466        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8467        let location = Location {
 8468            buffer: buffer.clone(),
 8469            range: range_start..range_start,
 8470        };
 8471        // Fill in the environmental variables from the tree-sitter captures
 8472        let mut captured_task_variables = TaskVariables::default();
 8473        for (capture_name, value) in tasks.extra_variables.clone() {
 8474            captured_task_variables.insert(
 8475                task::VariableName::Custom(capture_name.into()),
 8476                value.clone(),
 8477            );
 8478        }
 8479        project.update(cx, |project, cx| {
 8480            project.task_store().update(cx, |task_store, cx| {
 8481                task_store.task_context_for_location(captured_task_variables, location, cx)
 8482            })
 8483        })
 8484    }
 8485
 8486    pub fn spawn_nearest_task(
 8487        &mut self,
 8488        action: &SpawnNearestTask,
 8489        window: &mut Window,
 8490        cx: &mut Context<Self>,
 8491    ) {
 8492        let Some((workspace, _)) = self.workspace.clone() else {
 8493            return;
 8494        };
 8495        let Some(project) = self.project.clone() else {
 8496            return;
 8497        };
 8498
 8499        // Try to find a closest, enclosing node using tree-sitter that has a task
 8500        let Some((buffer, buffer_row, tasks)) = self
 8501            .find_enclosing_node_task(cx)
 8502            // Or find the task that's closest in row-distance.
 8503            .or_else(|| self.find_closest_task(cx))
 8504        else {
 8505            return;
 8506        };
 8507
 8508        let reveal_strategy = action.reveal;
 8509        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8510        cx.spawn_in(window, async move |_, cx| {
 8511            let context = task_context.await?;
 8512            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8513
 8514            let resolved = &mut resolved_task.resolved;
 8515            resolved.reveal = reveal_strategy;
 8516
 8517            workspace
 8518                .update_in(cx, |workspace, window, cx| {
 8519                    workspace.schedule_resolved_task(
 8520                        task_source_kind,
 8521                        resolved_task,
 8522                        false,
 8523                        window,
 8524                        cx,
 8525                    );
 8526                })
 8527                .ok()
 8528        })
 8529        .detach();
 8530    }
 8531
 8532    fn find_closest_task(
 8533        &mut self,
 8534        cx: &mut Context<Self>,
 8535    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8536        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8537
 8538        let ((buffer_id, row), tasks) = self
 8539            .tasks
 8540            .iter()
 8541            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8542
 8543        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8544        let tasks = Arc::new(tasks.to_owned());
 8545        Some((buffer, *row, tasks))
 8546    }
 8547
 8548    fn find_enclosing_node_task(
 8549        &mut self,
 8550        cx: &mut Context<Self>,
 8551    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8552        let snapshot = self.buffer.read(cx).snapshot(cx);
 8553        let offset = self.selections.newest::<usize>(cx).head();
 8554        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8555        let buffer_id = excerpt.buffer().remote_id();
 8556
 8557        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8558        let mut cursor = layer.node().walk();
 8559
 8560        while cursor.goto_first_child_for_byte(offset).is_some() {
 8561            if cursor.node().end_byte() == offset {
 8562                cursor.goto_next_sibling();
 8563            }
 8564        }
 8565
 8566        // Ascend to the smallest ancestor that contains the range and has a task.
 8567        loop {
 8568            let node = cursor.node();
 8569            let node_range = node.byte_range();
 8570            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8571
 8572            // Check if this node contains our offset
 8573            if node_range.start <= offset && node_range.end >= offset {
 8574                // If it contains offset, check for task
 8575                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8576                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8577                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8578                }
 8579            }
 8580
 8581            if !cursor.goto_parent() {
 8582                break;
 8583            }
 8584        }
 8585        None
 8586    }
 8587
 8588    fn render_run_indicator(
 8589        &self,
 8590        _style: &EditorStyle,
 8591        is_active: bool,
 8592        row: DisplayRow,
 8593        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8594        cx: &mut Context<Self>,
 8595    ) -> IconButton {
 8596        let color = Color::Muted;
 8597        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8598
 8599        IconButton::new(
 8600            ("run_indicator", row.0 as usize),
 8601            ui::IconName::PlayOutlined,
 8602        )
 8603        .shape(ui::IconButtonShape::Square)
 8604        .icon_size(IconSize::XSmall)
 8605        .icon_color(color)
 8606        .toggle_state(is_active)
 8607        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8608            let quick_launch = match e {
 8609                ClickEvent::Keyboard(_) => true,
 8610                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8611            };
 8612
 8613            window.focus(&editor.focus_handle(cx));
 8614            editor.toggle_code_actions(
 8615                &ToggleCodeActions {
 8616                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8617                    quick_launch,
 8618                },
 8619                window,
 8620                cx,
 8621            );
 8622        }))
 8623        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8624            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8625        }))
 8626    }
 8627
 8628    pub fn context_menu_visible(&self) -> bool {
 8629        !self.edit_prediction_preview_is_active()
 8630            && self
 8631                .context_menu
 8632                .borrow()
 8633                .as_ref()
 8634                .is_some_and(|menu| menu.visible())
 8635    }
 8636
 8637    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8638        self.context_menu
 8639            .borrow()
 8640            .as_ref()
 8641            .map(|menu| menu.origin())
 8642    }
 8643
 8644    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8645        self.context_menu_options = Some(options);
 8646    }
 8647
 8648    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8649    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8650
 8651    fn render_edit_prediction_popover(
 8652        &mut self,
 8653        text_bounds: &Bounds<Pixels>,
 8654        content_origin: gpui::Point<Pixels>,
 8655        right_margin: Pixels,
 8656        editor_snapshot: &EditorSnapshot,
 8657        visible_row_range: Range<DisplayRow>,
 8658        scroll_top: ScrollOffset,
 8659        scroll_bottom: ScrollOffset,
 8660        line_layouts: &[LineWithInvisibles],
 8661        line_height: Pixels,
 8662        scroll_position: gpui::Point<ScrollOffset>,
 8663        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8664        newest_selection_head: Option<DisplayPoint>,
 8665        editor_width: Pixels,
 8666        style: &EditorStyle,
 8667        window: &mut Window,
 8668        cx: &mut App,
 8669    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8670        if self.mode().is_minimap() {
 8671            return None;
 8672        }
 8673        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8674
 8675        if self.edit_prediction_visible_in_cursor_popover(true) {
 8676            return None;
 8677        }
 8678
 8679        match &active_edit_prediction.completion {
 8680            EditPrediction::MoveWithin { target, .. } => {
 8681                let target_display_point = target.to_display_point(editor_snapshot);
 8682
 8683                if self.edit_prediction_requires_modifier() {
 8684                    if !self.edit_prediction_preview_is_active() {
 8685                        return None;
 8686                    }
 8687
 8688                    self.render_edit_prediction_modifier_jump_popover(
 8689                        text_bounds,
 8690                        content_origin,
 8691                        visible_row_range,
 8692                        line_layouts,
 8693                        line_height,
 8694                        scroll_pixel_position,
 8695                        newest_selection_head,
 8696                        target_display_point,
 8697                        window,
 8698                        cx,
 8699                    )
 8700                } else {
 8701                    self.render_edit_prediction_eager_jump_popover(
 8702                        text_bounds,
 8703                        content_origin,
 8704                        editor_snapshot,
 8705                        visible_row_range,
 8706                        scroll_top,
 8707                        scroll_bottom,
 8708                        line_height,
 8709                        scroll_pixel_position,
 8710                        target_display_point,
 8711                        editor_width,
 8712                        window,
 8713                        cx,
 8714                    )
 8715                }
 8716            }
 8717            EditPrediction::Edit {
 8718                display_mode: EditDisplayMode::Inline,
 8719                ..
 8720            } => None,
 8721            EditPrediction::Edit {
 8722                display_mode: EditDisplayMode::TabAccept,
 8723                edits,
 8724                ..
 8725            } => {
 8726                let range = &edits.first()?.0;
 8727                let target_display_point = range.end.to_display_point(editor_snapshot);
 8728
 8729                self.render_edit_prediction_end_of_line_popover(
 8730                    "Accept",
 8731                    editor_snapshot,
 8732                    visible_row_range,
 8733                    target_display_point,
 8734                    line_height,
 8735                    scroll_pixel_position,
 8736                    content_origin,
 8737                    editor_width,
 8738                    window,
 8739                    cx,
 8740                )
 8741            }
 8742            EditPrediction::Edit {
 8743                edits,
 8744                edit_preview,
 8745                display_mode: EditDisplayMode::DiffPopover,
 8746                snapshot,
 8747            } => self.render_edit_prediction_diff_popover(
 8748                text_bounds,
 8749                content_origin,
 8750                right_margin,
 8751                editor_snapshot,
 8752                visible_row_range,
 8753                line_layouts,
 8754                line_height,
 8755                scroll_position,
 8756                scroll_pixel_position,
 8757                newest_selection_head,
 8758                editor_width,
 8759                style,
 8760                edits,
 8761                edit_preview,
 8762                snapshot,
 8763                window,
 8764                cx,
 8765            ),
 8766            EditPrediction::MoveOutside { snapshot, .. } => {
 8767                let file_name = snapshot
 8768                    .file()
 8769                    .map(|file| file.file_name(cx))
 8770                    .unwrap_or("untitled");
 8771                let mut element = self
 8772                    .render_edit_prediction_line_popover(
 8773                        format!("Jump to {file_name}"),
 8774                        Some(IconName::ZedPredict),
 8775                        window,
 8776                        cx,
 8777                    )
 8778                    .into_any();
 8779
 8780                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8781                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8782                let origin_y = text_bounds.size.height - size.height - px(30.);
 8783                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8784                element.prepaint_at(origin, window, cx);
 8785
 8786                Some((element, origin))
 8787            }
 8788        }
 8789    }
 8790
 8791    fn render_edit_prediction_modifier_jump_popover(
 8792        &mut self,
 8793        text_bounds: &Bounds<Pixels>,
 8794        content_origin: gpui::Point<Pixels>,
 8795        visible_row_range: Range<DisplayRow>,
 8796        line_layouts: &[LineWithInvisibles],
 8797        line_height: Pixels,
 8798        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8799        newest_selection_head: Option<DisplayPoint>,
 8800        target_display_point: DisplayPoint,
 8801        window: &mut Window,
 8802        cx: &mut App,
 8803    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8804        let scrolled_content_origin =
 8805            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8806
 8807        const SCROLL_PADDING_Y: Pixels = px(12.);
 8808
 8809        if target_display_point.row() < visible_row_range.start {
 8810            return self.render_edit_prediction_scroll_popover(
 8811                |_| SCROLL_PADDING_Y,
 8812                IconName::ArrowUp,
 8813                visible_row_range,
 8814                line_layouts,
 8815                newest_selection_head,
 8816                scrolled_content_origin,
 8817                window,
 8818                cx,
 8819            );
 8820        } else if target_display_point.row() >= visible_row_range.end {
 8821            return self.render_edit_prediction_scroll_popover(
 8822                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8823                IconName::ArrowDown,
 8824                visible_row_range,
 8825                line_layouts,
 8826                newest_selection_head,
 8827                scrolled_content_origin,
 8828                window,
 8829                cx,
 8830            );
 8831        }
 8832
 8833        const POLE_WIDTH: Pixels = px(2.);
 8834
 8835        let line_layout =
 8836            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8837        let target_column = target_display_point.column() as usize;
 8838
 8839        let target_x = line_layout.x_for_index(target_column);
 8840        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8841            - scroll_pixel_position.y;
 8842
 8843        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8844
 8845        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8846        border_color.l += 0.001;
 8847
 8848        let mut element = v_flex()
 8849            .items_end()
 8850            .when(flag_on_right, |el| el.items_start())
 8851            .child(if flag_on_right {
 8852                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8853                    .rounded_bl(px(0.))
 8854                    .rounded_tl(px(0.))
 8855                    .border_l_2()
 8856                    .border_color(border_color)
 8857            } else {
 8858                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8859                    .rounded_br(px(0.))
 8860                    .rounded_tr(px(0.))
 8861                    .border_r_2()
 8862                    .border_color(border_color)
 8863            })
 8864            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8865            .into_any();
 8866
 8867        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8868
 8869        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8870            - point(
 8871                if flag_on_right {
 8872                    POLE_WIDTH
 8873                } else {
 8874                    size.width - POLE_WIDTH
 8875                },
 8876                size.height - line_height,
 8877            );
 8878
 8879        origin.x = origin.x.max(content_origin.x);
 8880
 8881        element.prepaint_at(origin, window, cx);
 8882
 8883        Some((element, origin))
 8884    }
 8885
 8886    fn render_edit_prediction_scroll_popover(
 8887        &mut self,
 8888        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8889        scroll_icon: IconName,
 8890        visible_row_range: Range<DisplayRow>,
 8891        line_layouts: &[LineWithInvisibles],
 8892        newest_selection_head: Option<DisplayPoint>,
 8893        scrolled_content_origin: gpui::Point<Pixels>,
 8894        window: &mut Window,
 8895        cx: &mut App,
 8896    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8897        let mut element = self
 8898            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8899            .into_any();
 8900
 8901        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8902
 8903        let cursor = newest_selection_head?;
 8904        let cursor_row_layout =
 8905            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8906        let cursor_column = cursor.column() as usize;
 8907
 8908        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8909
 8910        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8911
 8912        element.prepaint_at(origin, window, cx);
 8913        Some((element, origin))
 8914    }
 8915
 8916    fn render_edit_prediction_eager_jump_popover(
 8917        &mut self,
 8918        text_bounds: &Bounds<Pixels>,
 8919        content_origin: gpui::Point<Pixels>,
 8920        editor_snapshot: &EditorSnapshot,
 8921        visible_row_range: Range<DisplayRow>,
 8922        scroll_top: ScrollOffset,
 8923        scroll_bottom: ScrollOffset,
 8924        line_height: Pixels,
 8925        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8926        target_display_point: DisplayPoint,
 8927        editor_width: Pixels,
 8928        window: &mut Window,
 8929        cx: &mut App,
 8930    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8931        if target_display_point.row().as_f64() < scroll_top {
 8932            let mut element = self
 8933                .render_edit_prediction_line_popover(
 8934                    "Jump to Edit",
 8935                    Some(IconName::ArrowUp),
 8936                    window,
 8937                    cx,
 8938                )
 8939                .into_any();
 8940
 8941            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8942            let offset = point(
 8943                (text_bounds.size.width - size.width) / 2.,
 8944                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8945            );
 8946
 8947            let origin = text_bounds.origin + offset;
 8948            element.prepaint_at(origin, window, cx);
 8949            Some((element, origin))
 8950        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8951            let mut element = self
 8952                .render_edit_prediction_line_popover(
 8953                    "Jump to Edit",
 8954                    Some(IconName::ArrowDown),
 8955                    window,
 8956                    cx,
 8957                )
 8958                .into_any();
 8959
 8960            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8961            let offset = point(
 8962                (text_bounds.size.width - size.width) / 2.,
 8963                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8964            );
 8965
 8966            let origin = text_bounds.origin + offset;
 8967            element.prepaint_at(origin, window, cx);
 8968            Some((element, origin))
 8969        } else {
 8970            self.render_edit_prediction_end_of_line_popover(
 8971                "Jump to Edit",
 8972                editor_snapshot,
 8973                visible_row_range,
 8974                target_display_point,
 8975                line_height,
 8976                scroll_pixel_position,
 8977                content_origin,
 8978                editor_width,
 8979                window,
 8980                cx,
 8981            )
 8982        }
 8983    }
 8984
 8985    fn render_edit_prediction_end_of_line_popover(
 8986        self: &mut Editor,
 8987        label: &'static str,
 8988        editor_snapshot: &EditorSnapshot,
 8989        visible_row_range: Range<DisplayRow>,
 8990        target_display_point: DisplayPoint,
 8991        line_height: Pixels,
 8992        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8993        content_origin: gpui::Point<Pixels>,
 8994        editor_width: Pixels,
 8995        window: &mut Window,
 8996        cx: &mut App,
 8997    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8998        let target_line_end = DisplayPoint::new(
 8999            target_display_point.row(),
 9000            editor_snapshot.line_len(target_display_point.row()),
 9001        );
 9002
 9003        let mut element = self
 9004            .render_edit_prediction_line_popover(label, None, window, cx)
 9005            .into_any();
 9006
 9007        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9008
 9009        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9010
 9011        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9012        let mut origin = start_point
 9013            + line_origin
 9014            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9015        origin.x = origin.x.max(content_origin.x);
 9016
 9017        let max_x = content_origin.x + editor_width - size.width;
 9018
 9019        if origin.x > max_x {
 9020            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9021
 9022            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9023                origin.y += offset;
 9024                IconName::ArrowUp
 9025            } else {
 9026                origin.y -= offset;
 9027                IconName::ArrowDown
 9028            };
 9029
 9030            element = self
 9031                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9032                .into_any();
 9033
 9034            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9035
 9036            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9037        }
 9038
 9039        element.prepaint_at(origin, window, cx);
 9040        Some((element, origin))
 9041    }
 9042
 9043    fn render_edit_prediction_diff_popover(
 9044        self: &Editor,
 9045        text_bounds: &Bounds<Pixels>,
 9046        content_origin: gpui::Point<Pixels>,
 9047        right_margin: Pixels,
 9048        editor_snapshot: &EditorSnapshot,
 9049        visible_row_range: Range<DisplayRow>,
 9050        line_layouts: &[LineWithInvisibles],
 9051        line_height: Pixels,
 9052        scroll_position: gpui::Point<ScrollOffset>,
 9053        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9054        newest_selection_head: Option<DisplayPoint>,
 9055        editor_width: Pixels,
 9056        style: &EditorStyle,
 9057        edits: &Vec<(Range<Anchor>, String)>,
 9058        edit_preview: &Option<language::EditPreview>,
 9059        snapshot: &language::BufferSnapshot,
 9060        window: &mut Window,
 9061        cx: &mut App,
 9062    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9063        let edit_start = edits
 9064            .first()
 9065            .unwrap()
 9066            .0
 9067            .start
 9068            .to_display_point(editor_snapshot);
 9069        let edit_end = edits
 9070            .last()
 9071            .unwrap()
 9072            .0
 9073            .end
 9074            .to_display_point(editor_snapshot);
 9075
 9076        let is_visible = visible_row_range.contains(&edit_start.row())
 9077            || visible_row_range.contains(&edit_end.row());
 9078        if !is_visible {
 9079            return None;
 9080        }
 9081
 9082        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9083            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9084        } else {
 9085            // Fallback for providers without edit_preview
 9086            crate::edit_prediction_fallback_text(edits, cx)
 9087        };
 9088
 9089        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9090        let line_count = highlighted_edits.text.lines().count();
 9091
 9092        const BORDER_WIDTH: Pixels = px(1.);
 9093
 9094        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9095        let has_keybind = keybind.is_some();
 9096
 9097        let mut element = h_flex()
 9098            .items_start()
 9099            .child(
 9100                h_flex()
 9101                    .bg(cx.theme().colors().editor_background)
 9102                    .border(BORDER_WIDTH)
 9103                    .shadow_xs()
 9104                    .border_color(cx.theme().colors().border)
 9105                    .rounded_l_lg()
 9106                    .when(line_count > 1, |el| el.rounded_br_lg())
 9107                    .pr_1()
 9108                    .child(styled_text),
 9109            )
 9110            .child(
 9111                h_flex()
 9112                    .h(line_height + BORDER_WIDTH * 2.)
 9113                    .px_1p5()
 9114                    .gap_1()
 9115                    // Workaround: For some reason, there's a gap if we don't do this
 9116                    .ml(-BORDER_WIDTH)
 9117                    .shadow(vec![gpui::BoxShadow {
 9118                        color: gpui::black().opacity(0.05),
 9119                        offset: point(px(1.), px(1.)),
 9120                        blur_radius: px(2.),
 9121                        spread_radius: px(0.),
 9122                    }])
 9123                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9124                    .border(BORDER_WIDTH)
 9125                    .border_color(cx.theme().colors().border)
 9126                    .rounded_r_lg()
 9127                    .id("edit_prediction_diff_popover_keybind")
 9128                    .when(!has_keybind, |el| {
 9129                        let status_colors = cx.theme().status();
 9130
 9131                        el.bg(status_colors.error_background)
 9132                            .border_color(status_colors.error.opacity(0.6))
 9133                            .child(Icon::new(IconName::Info).color(Color::Error))
 9134                            .cursor_default()
 9135                            .hoverable_tooltip(move |_window, cx| {
 9136                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9137                            })
 9138                    })
 9139                    .children(keybind),
 9140            )
 9141            .into_any();
 9142
 9143        let longest_row =
 9144            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9145        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9146            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9147        } else {
 9148            layout_line(
 9149                longest_row,
 9150                editor_snapshot,
 9151                style,
 9152                editor_width,
 9153                |_| false,
 9154                window,
 9155                cx,
 9156            )
 9157            .width
 9158        };
 9159
 9160        let viewport_bounds =
 9161            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9162                right: -right_margin,
 9163                ..Default::default()
 9164            });
 9165
 9166        let x_after_longest = Pixels::from(
 9167            ScrollPixelOffset::from(
 9168                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9169            ) - scroll_pixel_position.x,
 9170        );
 9171
 9172        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9173
 9174        // Fully visible if it can be displayed within the window (allow overlapping other
 9175        // panes). However, this is only allowed if the popover starts within text_bounds.
 9176        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9177            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9178
 9179        let mut origin = if can_position_to_the_right {
 9180            point(
 9181                x_after_longest,
 9182                text_bounds.origin.y
 9183                    + Pixels::from(
 9184                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9185                            - scroll_pixel_position.y,
 9186                    ),
 9187            )
 9188        } else {
 9189            let cursor_row = newest_selection_head.map(|head| head.row());
 9190            let above_edit = edit_start
 9191                .row()
 9192                .0
 9193                .checked_sub(line_count as u32)
 9194                .map(DisplayRow);
 9195            let below_edit = Some(edit_end.row() + 1);
 9196            let above_cursor =
 9197                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9198            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9199
 9200            // Place the edit popover adjacent to the edit if there is a location
 9201            // available that is onscreen and does not obscure the cursor. Otherwise,
 9202            // place it adjacent to the cursor.
 9203            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9204                .into_iter()
 9205                .flatten()
 9206                .find(|&start_row| {
 9207                    let end_row = start_row + line_count as u32;
 9208                    visible_row_range.contains(&start_row)
 9209                        && visible_row_range.contains(&end_row)
 9210                        && cursor_row
 9211                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9212                })?;
 9213
 9214            content_origin
 9215                + point(
 9216                    Pixels::from(-scroll_pixel_position.x),
 9217                    Pixels::from(
 9218                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9219                    ),
 9220                )
 9221        };
 9222
 9223        origin.x -= BORDER_WIDTH;
 9224
 9225        window.defer_draw(element, origin, 1);
 9226
 9227        // Do not return an element, since it will already be drawn due to defer_draw.
 9228        None
 9229    }
 9230
 9231    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9232        px(30.)
 9233    }
 9234
 9235    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9236        if self.read_only(cx) {
 9237            cx.theme().players().read_only()
 9238        } else {
 9239            self.style.as_ref().unwrap().local_player
 9240        }
 9241    }
 9242
 9243    fn render_edit_prediction_accept_keybind(
 9244        &self,
 9245        window: &mut Window,
 9246        cx: &App,
 9247    ) -> Option<AnyElement> {
 9248        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9249        let accept_keystroke = accept_binding.keystroke()?;
 9250
 9251        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9252
 9253        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9254            Color::Accent
 9255        } else {
 9256            Color::Muted
 9257        };
 9258
 9259        h_flex()
 9260            .px_0p5()
 9261            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9262            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9263            .text_size(TextSize::XSmall.rems(cx))
 9264            .child(h_flex().children(ui::render_modifiers(
 9265                accept_keystroke.modifiers(),
 9266                PlatformStyle::platform(),
 9267                Some(modifiers_color),
 9268                Some(IconSize::XSmall.rems().into()),
 9269                true,
 9270            )))
 9271            .when(is_platform_style_mac, |parent| {
 9272                parent.child(accept_keystroke.key().to_string())
 9273            })
 9274            .when(!is_platform_style_mac, |parent| {
 9275                parent.child(
 9276                    Key::new(
 9277                        util::capitalize(accept_keystroke.key()),
 9278                        Some(Color::Default),
 9279                    )
 9280                    .size(Some(IconSize::XSmall.rems().into())),
 9281                )
 9282            })
 9283            .into_any()
 9284            .into()
 9285    }
 9286
 9287    fn render_edit_prediction_line_popover(
 9288        &self,
 9289        label: impl Into<SharedString>,
 9290        icon: Option<IconName>,
 9291        window: &mut Window,
 9292        cx: &App,
 9293    ) -> Stateful<Div> {
 9294        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9295
 9296        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9297        let has_keybind = keybind.is_some();
 9298
 9299        h_flex()
 9300            .id("ep-line-popover")
 9301            .py_0p5()
 9302            .pl_1()
 9303            .pr(padding_right)
 9304            .gap_1()
 9305            .rounded_md()
 9306            .border_1()
 9307            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9308            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9309            .shadow_xs()
 9310            .when(!has_keybind, |el| {
 9311                let status_colors = cx.theme().status();
 9312
 9313                el.bg(status_colors.error_background)
 9314                    .border_color(status_colors.error.opacity(0.6))
 9315                    .pl_2()
 9316                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9317                    .cursor_default()
 9318                    .hoverable_tooltip(move |_window, cx| {
 9319                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9320                    })
 9321            })
 9322            .children(keybind)
 9323            .child(
 9324                Label::new(label)
 9325                    .size(LabelSize::Small)
 9326                    .when(!has_keybind, |el| {
 9327                        el.color(cx.theme().status().error.into()).strikethrough()
 9328                    }),
 9329            )
 9330            .when(!has_keybind, |el| {
 9331                el.child(
 9332                    h_flex().ml_1().child(
 9333                        Icon::new(IconName::Info)
 9334                            .size(IconSize::Small)
 9335                            .color(cx.theme().status().error.into()),
 9336                    ),
 9337                )
 9338            })
 9339            .when_some(icon, |element, icon| {
 9340                element.child(
 9341                    div()
 9342                        .mt(px(1.5))
 9343                        .child(Icon::new(icon).size(IconSize::Small)),
 9344                )
 9345            })
 9346    }
 9347
 9348    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9349        let accent_color = cx.theme().colors().text_accent;
 9350        let editor_bg_color = cx.theme().colors().editor_background;
 9351        editor_bg_color.blend(accent_color.opacity(0.1))
 9352    }
 9353
 9354    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9355        let accent_color = cx.theme().colors().text_accent;
 9356        let editor_bg_color = cx.theme().colors().editor_background;
 9357        editor_bg_color.blend(accent_color.opacity(0.6))
 9358    }
 9359    fn get_prediction_provider_icon_name(
 9360        provider: &Option<RegisteredEditPredictionProvider>,
 9361    ) -> IconName {
 9362        match provider {
 9363            Some(provider) => match provider.provider.name() {
 9364                "copilot" => IconName::Copilot,
 9365                "supermaven" => IconName::Supermaven,
 9366                _ => IconName::ZedPredict,
 9367            },
 9368            None => IconName::ZedPredict,
 9369        }
 9370    }
 9371
 9372    fn render_edit_prediction_cursor_popover(
 9373        &self,
 9374        min_width: Pixels,
 9375        max_width: Pixels,
 9376        cursor_point: Point,
 9377        style: &EditorStyle,
 9378        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9379        _window: &Window,
 9380        cx: &mut Context<Editor>,
 9381    ) -> Option<AnyElement> {
 9382        let provider = self.edit_prediction_provider.as_ref()?;
 9383        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9384
 9385        let is_refreshing = provider.provider.is_refreshing(cx);
 9386
 9387        fn pending_completion_container(icon: IconName) -> Div {
 9388            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9389        }
 9390
 9391        let completion = match &self.active_edit_prediction {
 9392            Some(prediction) => {
 9393                if !self.has_visible_completions_menu() {
 9394                    const RADIUS: Pixels = px(6.);
 9395                    const BORDER_WIDTH: Pixels = px(1.);
 9396
 9397                    return Some(
 9398                        h_flex()
 9399                            .elevation_2(cx)
 9400                            .border(BORDER_WIDTH)
 9401                            .border_color(cx.theme().colors().border)
 9402                            .when(accept_keystroke.is_none(), |el| {
 9403                                el.border_color(cx.theme().status().error)
 9404                            })
 9405                            .rounded(RADIUS)
 9406                            .rounded_tl(px(0.))
 9407                            .overflow_hidden()
 9408                            .child(div().px_1p5().child(match &prediction.completion {
 9409                                EditPrediction::MoveWithin { target, snapshot } => {
 9410                                    use text::ToPoint as _;
 9411                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9412                                    {
 9413                                        Icon::new(IconName::ZedPredictDown)
 9414                                    } else {
 9415                                        Icon::new(IconName::ZedPredictUp)
 9416                                    }
 9417                                }
 9418                                EditPrediction::MoveOutside { .. } => {
 9419                                    // TODO [zeta2] custom icon for external jump?
 9420                                    Icon::new(provider_icon)
 9421                                }
 9422                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9423                            }))
 9424                            .child(
 9425                                h_flex()
 9426                                    .gap_1()
 9427                                    .py_1()
 9428                                    .px_2()
 9429                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9430                                    .border_l_1()
 9431                                    .border_color(cx.theme().colors().border)
 9432                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9433                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9434                                        el.child(
 9435                                            Label::new("Hold")
 9436                                                .size(LabelSize::Small)
 9437                                                .when(accept_keystroke.is_none(), |el| {
 9438                                                    el.strikethrough()
 9439                                                })
 9440                                                .line_height_style(LineHeightStyle::UiLabel),
 9441                                        )
 9442                                    })
 9443                                    .id("edit_prediction_cursor_popover_keybind")
 9444                                    .when(accept_keystroke.is_none(), |el| {
 9445                                        let status_colors = cx.theme().status();
 9446
 9447                                        el.bg(status_colors.error_background)
 9448                                            .border_color(status_colors.error.opacity(0.6))
 9449                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9450                                            .cursor_default()
 9451                                            .hoverable_tooltip(move |_window, cx| {
 9452                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9453                                                    .into()
 9454                                            })
 9455                                    })
 9456                                    .when_some(
 9457                                        accept_keystroke.as_ref(),
 9458                                        |el, accept_keystroke| {
 9459                                            el.child(h_flex().children(ui::render_modifiers(
 9460                                                accept_keystroke.modifiers(),
 9461                                                PlatformStyle::platform(),
 9462                                                Some(Color::Default),
 9463                                                Some(IconSize::XSmall.rems().into()),
 9464                                                false,
 9465                                            )))
 9466                                        },
 9467                                    ),
 9468                            )
 9469                            .into_any(),
 9470                    );
 9471                }
 9472
 9473                self.render_edit_prediction_cursor_popover_preview(
 9474                    prediction,
 9475                    cursor_point,
 9476                    style,
 9477                    cx,
 9478                )?
 9479            }
 9480
 9481            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9482                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9483                    stale_completion,
 9484                    cursor_point,
 9485                    style,
 9486                    cx,
 9487                )?,
 9488
 9489                None => pending_completion_container(provider_icon)
 9490                    .child(Label::new("...").size(LabelSize::Small)),
 9491            },
 9492
 9493            None => pending_completion_container(provider_icon)
 9494                .child(Label::new("...").size(LabelSize::Small)),
 9495        };
 9496
 9497        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9498            completion
 9499                .with_animation(
 9500                    "loading-completion",
 9501                    Animation::new(Duration::from_secs(2))
 9502                        .repeat()
 9503                        .with_easing(pulsating_between(0.4, 0.8)),
 9504                    |label, delta| label.opacity(delta),
 9505                )
 9506                .into_any_element()
 9507        } else {
 9508            completion.into_any_element()
 9509        };
 9510
 9511        let has_completion = self.active_edit_prediction.is_some();
 9512
 9513        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9514        Some(
 9515            h_flex()
 9516                .min_w(min_width)
 9517                .max_w(max_width)
 9518                .flex_1()
 9519                .elevation_2(cx)
 9520                .border_color(cx.theme().colors().border)
 9521                .child(
 9522                    div()
 9523                        .flex_1()
 9524                        .py_1()
 9525                        .px_2()
 9526                        .overflow_hidden()
 9527                        .child(completion),
 9528                )
 9529                .when_some(accept_keystroke, |el, accept_keystroke| {
 9530                    if !accept_keystroke.modifiers().modified() {
 9531                        return el;
 9532                    }
 9533
 9534                    el.child(
 9535                        h_flex()
 9536                            .h_full()
 9537                            .border_l_1()
 9538                            .rounded_r_lg()
 9539                            .border_color(cx.theme().colors().border)
 9540                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9541                            .gap_1()
 9542                            .py_1()
 9543                            .px_2()
 9544                            .child(
 9545                                h_flex()
 9546                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9547                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9548                                    .child(h_flex().children(ui::render_modifiers(
 9549                                        accept_keystroke.modifiers(),
 9550                                        PlatformStyle::platform(),
 9551                                        Some(if !has_completion {
 9552                                            Color::Muted
 9553                                        } else {
 9554                                            Color::Default
 9555                                        }),
 9556                                        None,
 9557                                        false,
 9558                                    ))),
 9559                            )
 9560                            .child(Label::new("Preview").into_any_element())
 9561                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9562                    )
 9563                })
 9564                .into_any(),
 9565        )
 9566    }
 9567
 9568    fn render_edit_prediction_cursor_popover_preview(
 9569        &self,
 9570        completion: &EditPredictionState,
 9571        cursor_point: Point,
 9572        style: &EditorStyle,
 9573        cx: &mut Context<Editor>,
 9574    ) -> Option<Div> {
 9575        use text::ToPoint as _;
 9576
 9577        fn render_relative_row_jump(
 9578            prefix: impl Into<String>,
 9579            current_row: u32,
 9580            target_row: u32,
 9581        ) -> Div {
 9582            let (row_diff, arrow) = if target_row < current_row {
 9583                (current_row - target_row, IconName::ArrowUp)
 9584            } else {
 9585                (target_row - current_row, IconName::ArrowDown)
 9586            };
 9587
 9588            h_flex()
 9589                .child(
 9590                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9591                        .color(Color::Muted)
 9592                        .size(LabelSize::Small),
 9593                )
 9594                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9595        }
 9596
 9597        let supports_jump = self
 9598            .edit_prediction_provider
 9599            .as_ref()
 9600            .map(|provider| provider.provider.supports_jump_to_edit())
 9601            .unwrap_or(true);
 9602
 9603        match &completion.completion {
 9604            EditPrediction::MoveWithin {
 9605                target, snapshot, ..
 9606            } => {
 9607                if !supports_jump {
 9608                    return None;
 9609                }
 9610
 9611                Some(
 9612                    h_flex()
 9613                        .px_2()
 9614                        .gap_2()
 9615                        .flex_1()
 9616                        .child(
 9617                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9618                                Icon::new(IconName::ZedPredictDown)
 9619                            } else {
 9620                                Icon::new(IconName::ZedPredictUp)
 9621                            },
 9622                        )
 9623                        .child(Label::new("Jump to Edit")),
 9624                )
 9625            }
 9626            EditPrediction::MoveOutside { snapshot, .. } => {
 9627                let file_name = snapshot
 9628                    .file()
 9629                    .map(|file| file.file_name(cx))
 9630                    .unwrap_or("untitled");
 9631                Some(
 9632                    h_flex()
 9633                        .px_2()
 9634                        .gap_2()
 9635                        .flex_1()
 9636                        .child(Icon::new(IconName::ZedPredict))
 9637                        .child(Label::new(format!("Jump to {file_name}"))),
 9638                )
 9639            }
 9640            EditPrediction::Edit {
 9641                edits,
 9642                edit_preview,
 9643                snapshot,
 9644                display_mode: _,
 9645            } => {
 9646                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9647
 9648                let (highlighted_edits, has_more_lines) =
 9649                    if let Some(edit_preview) = edit_preview.as_ref() {
 9650                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9651                            .first_line_preview()
 9652                    } else {
 9653                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9654                    };
 9655
 9656                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9657                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9658
 9659                let preview = h_flex()
 9660                    .gap_1()
 9661                    .min_w_16()
 9662                    .child(styled_text)
 9663                    .when(has_more_lines, |parent| parent.child(""));
 9664
 9665                let left = if supports_jump && first_edit_row != cursor_point.row {
 9666                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9667                        .into_any_element()
 9668                } else {
 9669                    let icon_name =
 9670                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9671                    Icon::new(icon_name).into_any_element()
 9672                };
 9673
 9674                Some(
 9675                    h_flex()
 9676                        .h_full()
 9677                        .flex_1()
 9678                        .gap_2()
 9679                        .pr_1()
 9680                        .overflow_x_hidden()
 9681                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9682                        .child(left)
 9683                        .child(preview),
 9684                )
 9685            }
 9686        }
 9687    }
 9688
 9689    pub fn render_context_menu(
 9690        &self,
 9691        style: &EditorStyle,
 9692        max_height_in_lines: u32,
 9693        window: &mut Window,
 9694        cx: &mut Context<Editor>,
 9695    ) -> Option<AnyElement> {
 9696        let menu = self.context_menu.borrow();
 9697        let menu = menu.as_ref()?;
 9698        if !menu.visible() {
 9699            return None;
 9700        };
 9701        Some(menu.render(style, max_height_in_lines, window, cx))
 9702    }
 9703
 9704    fn render_context_menu_aside(
 9705        &mut self,
 9706        max_size: Size<Pixels>,
 9707        window: &mut Window,
 9708        cx: &mut Context<Editor>,
 9709    ) -> Option<AnyElement> {
 9710        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9711            if menu.visible() {
 9712                menu.render_aside(max_size, window, cx)
 9713            } else {
 9714                None
 9715            }
 9716        })
 9717    }
 9718
 9719    fn hide_context_menu(
 9720        &mut self,
 9721        window: &mut Window,
 9722        cx: &mut Context<Self>,
 9723    ) -> Option<CodeContextMenu> {
 9724        cx.notify();
 9725        self.completion_tasks.clear();
 9726        let context_menu = self.context_menu.borrow_mut().take();
 9727        self.stale_edit_prediction_in_menu.take();
 9728        self.update_visible_edit_prediction(window, cx);
 9729        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9730            && let Some(completion_provider) = &self.completion_provider
 9731        {
 9732            completion_provider.selection_changed(None, window, cx);
 9733        }
 9734        context_menu
 9735    }
 9736
 9737    fn show_snippet_choices(
 9738        &mut self,
 9739        choices: &Vec<String>,
 9740        selection: Range<Anchor>,
 9741        cx: &mut Context<Self>,
 9742    ) {
 9743        let Some((_, buffer, _)) = self
 9744            .buffer()
 9745            .read(cx)
 9746            .excerpt_containing(selection.start, cx)
 9747        else {
 9748            return;
 9749        };
 9750        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9751        else {
 9752            return;
 9753        };
 9754        if buffer != end_buffer {
 9755            log::error!("expected anchor range to have matching buffer IDs");
 9756            return;
 9757        }
 9758
 9759        let id = post_inc(&mut self.next_completion_id);
 9760        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9761        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9762            CompletionsMenu::new_snippet_choices(
 9763                id,
 9764                true,
 9765                choices,
 9766                selection,
 9767                buffer,
 9768                snippet_sort_order,
 9769            ),
 9770        ));
 9771    }
 9772
 9773    pub fn insert_snippet(
 9774        &mut self,
 9775        insertion_ranges: &[Range<usize>],
 9776        snippet: Snippet,
 9777        window: &mut Window,
 9778        cx: &mut Context<Self>,
 9779    ) -> Result<()> {
 9780        struct Tabstop<T> {
 9781            is_end_tabstop: bool,
 9782            ranges: Vec<Range<T>>,
 9783            choices: Option<Vec<String>>,
 9784        }
 9785
 9786        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9787            let snippet_text: Arc<str> = snippet.text.clone().into();
 9788            let edits = insertion_ranges
 9789                .iter()
 9790                .cloned()
 9791                .map(|range| (range, snippet_text.clone()));
 9792            let autoindent_mode = AutoindentMode::Block {
 9793                original_indent_columns: Vec::new(),
 9794            };
 9795            buffer.edit(edits, Some(autoindent_mode), cx);
 9796
 9797            let snapshot = &*buffer.read(cx);
 9798            let snippet = &snippet;
 9799            snippet
 9800                .tabstops
 9801                .iter()
 9802                .map(|tabstop| {
 9803                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9804                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9805                    });
 9806                    let mut tabstop_ranges = tabstop
 9807                        .ranges
 9808                        .iter()
 9809                        .flat_map(|tabstop_range| {
 9810                            let mut delta = 0_isize;
 9811                            insertion_ranges.iter().map(move |insertion_range| {
 9812                                let insertion_start = insertion_range.start as isize + delta;
 9813                                delta +=
 9814                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9815
 9816                                let start = ((insertion_start + tabstop_range.start) as usize)
 9817                                    .min(snapshot.len());
 9818                                let end = ((insertion_start + tabstop_range.end) as usize)
 9819                                    .min(snapshot.len());
 9820                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9821                            })
 9822                        })
 9823                        .collect::<Vec<_>>();
 9824                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9825
 9826                    Tabstop {
 9827                        is_end_tabstop,
 9828                        ranges: tabstop_ranges,
 9829                        choices: tabstop.choices.clone(),
 9830                    }
 9831                })
 9832                .collect::<Vec<_>>()
 9833        });
 9834        if let Some(tabstop) = tabstops.first() {
 9835            self.change_selections(Default::default(), window, cx, |s| {
 9836                // Reverse order so that the first range is the newest created selection.
 9837                // Completions will use it and autoscroll will prioritize it.
 9838                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9839            });
 9840
 9841            if let Some(choices) = &tabstop.choices
 9842                && let Some(selection) = tabstop.ranges.first()
 9843            {
 9844                self.show_snippet_choices(choices, selection.clone(), cx)
 9845            }
 9846
 9847            // If we're already at the last tabstop and it's at the end of the snippet,
 9848            // we're done, we don't need to keep the state around.
 9849            if !tabstop.is_end_tabstop {
 9850                let choices = tabstops
 9851                    .iter()
 9852                    .map(|tabstop| tabstop.choices.clone())
 9853                    .collect();
 9854
 9855                let ranges = tabstops
 9856                    .into_iter()
 9857                    .map(|tabstop| tabstop.ranges)
 9858                    .collect::<Vec<_>>();
 9859
 9860                self.snippet_stack.push(SnippetState {
 9861                    active_index: 0,
 9862                    ranges,
 9863                    choices,
 9864                });
 9865            }
 9866
 9867            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9868            if self.autoclose_regions.is_empty() {
 9869                let snapshot = self.buffer.read(cx).snapshot(cx);
 9870                let mut all_selections = self.selections.all::<Point>(cx);
 9871                for selection in &mut all_selections {
 9872                    let selection_head = selection.head();
 9873                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9874                        continue;
 9875                    };
 9876
 9877                    let mut bracket_pair = None;
 9878                    let max_lookup_length = scope
 9879                        .brackets()
 9880                        .map(|(pair, _)| {
 9881                            pair.start
 9882                                .as_str()
 9883                                .chars()
 9884                                .count()
 9885                                .max(pair.end.as_str().chars().count())
 9886                        })
 9887                        .max();
 9888                    if let Some(max_lookup_length) = max_lookup_length {
 9889                        let next_text = snapshot
 9890                            .chars_at(selection_head)
 9891                            .take(max_lookup_length)
 9892                            .collect::<String>();
 9893                        let prev_text = snapshot
 9894                            .reversed_chars_at(selection_head)
 9895                            .take(max_lookup_length)
 9896                            .collect::<String>();
 9897
 9898                        for (pair, enabled) in scope.brackets() {
 9899                            if enabled
 9900                                && pair.close
 9901                                && prev_text.starts_with(pair.start.as_str())
 9902                                && next_text.starts_with(pair.end.as_str())
 9903                            {
 9904                                bracket_pair = Some(pair.clone());
 9905                                break;
 9906                            }
 9907                        }
 9908                    }
 9909
 9910                    if let Some(pair) = bracket_pair {
 9911                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9912                        let autoclose_enabled =
 9913                            self.use_autoclose && snapshot_settings.use_autoclose;
 9914                        if autoclose_enabled {
 9915                            let start = snapshot.anchor_after(selection_head);
 9916                            let end = snapshot.anchor_after(selection_head);
 9917                            self.autoclose_regions.push(AutocloseRegion {
 9918                                selection_id: selection.id,
 9919                                range: start..end,
 9920                                pair,
 9921                            });
 9922                        }
 9923                    }
 9924                }
 9925            }
 9926        }
 9927        Ok(())
 9928    }
 9929
 9930    pub fn move_to_next_snippet_tabstop(
 9931        &mut self,
 9932        window: &mut Window,
 9933        cx: &mut Context<Self>,
 9934    ) -> bool {
 9935        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9936    }
 9937
 9938    pub fn move_to_prev_snippet_tabstop(
 9939        &mut self,
 9940        window: &mut Window,
 9941        cx: &mut Context<Self>,
 9942    ) -> bool {
 9943        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9944    }
 9945
 9946    pub fn move_to_snippet_tabstop(
 9947        &mut self,
 9948        bias: Bias,
 9949        window: &mut Window,
 9950        cx: &mut Context<Self>,
 9951    ) -> bool {
 9952        if let Some(mut snippet) = self.snippet_stack.pop() {
 9953            match bias {
 9954                Bias::Left => {
 9955                    if snippet.active_index > 0 {
 9956                        snippet.active_index -= 1;
 9957                    } else {
 9958                        self.snippet_stack.push(snippet);
 9959                        return false;
 9960                    }
 9961                }
 9962                Bias::Right => {
 9963                    if snippet.active_index + 1 < snippet.ranges.len() {
 9964                        snippet.active_index += 1;
 9965                    } else {
 9966                        self.snippet_stack.push(snippet);
 9967                        return false;
 9968                    }
 9969                }
 9970            }
 9971            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9972                self.change_selections(Default::default(), window, cx, |s| {
 9973                    // Reverse order so that the first range is the newest created selection.
 9974                    // Completions will use it and autoscroll will prioritize it.
 9975                    s.select_ranges(current_ranges.iter().rev().cloned())
 9976                });
 9977
 9978                if let Some(choices) = &snippet.choices[snippet.active_index]
 9979                    && let Some(selection) = current_ranges.first()
 9980                {
 9981                    self.show_snippet_choices(choices, selection.clone(), cx);
 9982                }
 9983
 9984                // If snippet state is not at the last tabstop, push it back on the stack
 9985                if snippet.active_index + 1 < snippet.ranges.len() {
 9986                    self.snippet_stack.push(snippet);
 9987                }
 9988                return true;
 9989            }
 9990        }
 9991
 9992        false
 9993    }
 9994
 9995    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9996        self.transact(window, cx, |this, window, cx| {
 9997            this.select_all(&SelectAll, window, cx);
 9998            this.insert("", window, cx);
 9999        });
10000    }
10001
10002    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10003        if self.read_only(cx) {
10004            return;
10005        }
10006        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10007        self.transact(window, cx, |this, window, cx| {
10008            this.select_autoclose_pair(window, cx);
10009            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10010            if !this.linked_edit_ranges.is_empty() {
10011                let selections = this.selections.all::<MultiBufferPoint>(cx);
10012                let snapshot = this.buffer.read(cx).snapshot(cx);
10013
10014                for selection in selections.iter() {
10015                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10016                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10017                    if selection_start.buffer_id != selection_end.buffer_id {
10018                        continue;
10019                    }
10020                    if let Some(ranges) =
10021                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10022                    {
10023                        for (buffer, entries) in ranges {
10024                            linked_ranges.entry(buffer).or_default().extend(entries);
10025                        }
10026                    }
10027                }
10028            }
10029
10030            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10031            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10032            for selection in &mut selections {
10033                if selection.is_empty() {
10034                    let old_head = selection.head();
10035                    let mut new_head =
10036                        movement::left(&display_map, old_head.to_display_point(&display_map))
10037                            .to_point(&display_map);
10038                    if let Some((buffer, line_buffer_range)) = display_map
10039                        .buffer_snapshot()
10040                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10041                    {
10042                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10043                        let indent_len = match indent_size.kind {
10044                            IndentKind::Space => {
10045                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10046                            }
10047                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10048                        };
10049                        if old_head.column <= indent_size.len && old_head.column > 0 {
10050                            let indent_len = indent_len.get();
10051                            new_head = cmp::min(
10052                                new_head,
10053                                MultiBufferPoint::new(
10054                                    old_head.row,
10055                                    ((old_head.column - 1) / indent_len) * indent_len,
10056                                ),
10057                            );
10058                        }
10059                    }
10060
10061                    selection.set_head(new_head, SelectionGoal::None);
10062                }
10063            }
10064
10065            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10066            this.insert("", window, cx);
10067            let empty_str: Arc<str> = Arc::from("");
10068            for (buffer, edits) in linked_ranges {
10069                let snapshot = buffer.read(cx).snapshot();
10070                use text::ToPoint as TP;
10071
10072                let edits = edits
10073                    .into_iter()
10074                    .map(|range| {
10075                        let end_point = TP::to_point(&range.end, &snapshot);
10076                        let mut start_point = TP::to_point(&range.start, &snapshot);
10077
10078                        if end_point == start_point {
10079                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10080                                .saturating_sub(1);
10081                            start_point =
10082                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10083                        };
10084
10085                        (start_point..end_point, empty_str.clone())
10086                    })
10087                    .sorted_by_key(|(range, _)| range.start)
10088                    .collect::<Vec<_>>();
10089                buffer.update(cx, |this, cx| {
10090                    this.edit(edits, None, cx);
10091                })
10092            }
10093            this.refresh_edit_prediction(true, false, window, cx);
10094            refresh_linked_ranges(this, window, cx);
10095        });
10096    }
10097
10098    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.read_only(cx) {
10100            return;
10101        }
10102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10103        self.transact(window, cx, |this, window, cx| {
10104            this.change_selections(Default::default(), window, cx, |s| {
10105                s.move_with(|map, selection| {
10106                    if selection.is_empty() {
10107                        let cursor = movement::right(map, selection.head());
10108                        selection.end = cursor;
10109                        selection.reversed = true;
10110                        selection.goal = SelectionGoal::None;
10111                    }
10112                })
10113            });
10114            this.insert("", window, cx);
10115            this.refresh_edit_prediction(true, false, window, cx);
10116        });
10117    }
10118
10119    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10120        if self.mode.is_single_line() {
10121            cx.propagate();
10122            return;
10123        }
10124
10125        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10126        if self.move_to_prev_snippet_tabstop(window, cx) {
10127            return;
10128        }
10129        self.outdent(&Outdent, window, cx);
10130    }
10131
10132    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10133        if self.mode.is_single_line() {
10134            cx.propagate();
10135            return;
10136        }
10137
10138        if self.move_to_next_snippet_tabstop(window, cx) {
10139            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10140            return;
10141        }
10142        if self.read_only(cx) {
10143            return;
10144        }
10145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10146        let mut selections = self.selections.all_adjusted(cx);
10147        let buffer = self.buffer.read(cx);
10148        let snapshot = buffer.snapshot(cx);
10149        let rows_iter = selections.iter().map(|s| s.head().row);
10150        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10151
10152        let has_some_cursor_in_whitespace = selections
10153            .iter()
10154            .filter(|selection| selection.is_empty())
10155            .any(|selection| {
10156                let cursor = selection.head();
10157                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10158                cursor.column < current_indent.len
10159            });
10160
10161        let mut edits = Vec::new();
10162        let mut prev_edited_row = 0;
10163        let mut row_delta = 0;
10164        for selection in &mut selections {
10165            if selection.start.row != prev_edited_row {
10166                row_delta = 0;
10167            }
10168            prev_edited_row = selection.end.row;
10169
10170            // If the selection is non-empty, then increase the indentation of the selected lines.
10171            if !selection.is_empty() {
10172                row_delta =
10173                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10174                continue;
10175            }
10176
10177            let cursor = selection.head();
10178            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10179            if let Some(suggested_indent) =
10180                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10181            {
10182                // Don't do anything if already at suggested indent
10183                // and there is any other cursor which is not
10184                if has_some_cursor_in_whitespace
10185                    && cursor.column == current_indent.len
10186                    && current_indent.len == suggested_indent.len
10187                {
10188                    continue;
10189                }
10190
10191                // Adjust line and move cursor to suggested indent
10192                // if cursor is not at suggested indent
10193                if cursor.column < suggested_indent.len
10194                    && cursor.column <= current_indent.len
10195                    && current_indent.len <= suggested_indent.len
10196                {
10197                    selection.start = Point::new(cursor.row, suggested_indent.len);
10198                    selection.end = selection.start;
10199                    if row_delta == 0 {
10200                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10201                            cursor.row,
10202                            current_indent,
10203                            suggested_indent,
10204                        ));
10205                        row_delta = suggested_indent.len - current_indent.len;
10206                    }
10207                    continue;
10208                }
10209
10210                // If current indent is more than suggested indent
10211                // only move cursor to current indent and skip indent
10212                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10213                    selection.start = Point::new(cursor.row, current_indent.len);
10214                    selection.end = selection.start;
10215                    continue;
10216                }
10217            }
10218
10219            // Otherwise, insert a hard or soft tab.
10220            let settings = buffer.language_settings_at(cursor, cx);
10221            let tab_size = if settings.hard_tabs {
10222                IndentSize::tab()
10223            } else {
10224                let tab_size = settings.tab_size.get();
10225                let indent_remainder = snapshot
10226                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10227                    .flat_map(str::chars)
10228                    .fold(row_delta % tab_size, |counter: u32, c| {
10229                        if c == '\t' {
10230                            0
10231                        } else {
10232                            (counter + 1) % tab_size
10233                        }
10234                    });
10235
10236                let chars_to_next_tab_stop = tab_size - indent_remainder;
10237                IndentSize::spaces(chars_to_next_tab_stop)
10238            };
10239            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10240            selection.end = selection.start;
10241            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10242            row_delta += tab_size.len;
10243        }
10244
10245        self.transact(window, cx, |this, window, cx| {
10246            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10247            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10248            this.refresh_edit_prediction(true, false, window, cx);
10249        });
10250    }
10251
10252    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10253        if self.read_only(cx) {
10254            return;
10255        }
10256        if self.mode.is_single_line() {
10257            cx.propagate();
10258            return;
10259        }
10260
10261        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10262        let mut selections = self.selections.all::<Point>(cx);
10263        let mut prev_edited_row = 0;
10264        let mut row_delta = 0;
10265        let mut edits = Vec::new();
10266        let buffer = self.buffer.read(cx);
10267        let snapshot = buffer.snapshot(cx);
10268        for selection in &mut selections {
10269            if selection.start.row != prev_edited_row {
10270                row_delta = 0;
10271            }
10272            prev_edited_row = selection.end.row;
10273
10274            row_delta =
10275                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10276        }
10277
10278        self.transact(window, cx, |this, window, cx| {
10279            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10280            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10281        });
10282    }
10283
10284    fn indent_selection(
10285        buffer: &MultiBuffer,
10286        snapshot: &MultiBufferSnapshot,
10287        selection: &mut Selection<Point>,
10288        edits: &mut Vec<(Range<Point>, String)>,
10289        delta_for_start_row: u32,
10290        cx: &App,
10291    ) -> u32 {
10292        let settings = buffer.language_settings_at(selection.start, cx);
10293        let tab_size = settings.tab_size.get();
10294        let indent_kind = if settings.hard_tabs {
10295            IndentKind::Tab
10296        } else {
10297            IndentKind::Space
10298        };
10299        let mut start_row = selection.start.row;
10300        let mut end_row = selection.end.row + 1;
10301
10302        // If a selection ends at the beginning of a line, don't indent
10303        // that last line.
10304        if selection.end.column == 0 && selection.end.row > selection.start.row {
10305            end_row -= 1;
10306        }
10307
10308        // Avoid re-indenting a row that has already been indented by a
10309        // previous selection, but still update this selection's column
10310        // to reflect that indentation.
10311        if delta_for_start_row > 0 {
10312            start_row += 1;
10313            selection.start.column += delta_for_start_row;
10314            if selection.end.row == selection.start.row {
10315                selection.end.column += delta_for_start_row;
10316            }
10317        }
10318
10319        let mut delta_for_end_row = 0;
10320        let has_multiple_rows = start_row + 1 != end_row;
10321        for row in start_row..end_row {
10322            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10323            let indent_delta = match (current_indent.kind, indent_kind) {
10324                (IndentKind::Space, IndentKind::Space) => {
10325                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10326                    IndentSize::spaces(columns_to_next_tab_stop)
10327                }
10328                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10329                (_, IndentKind::Tab) => IndentSize::tab(),
10330            };
10331
10332            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10333                0
10334            } else {
10335                selection.start.column
10336            };
10337            let row_start = Point::new(row, start);
10338            edits.push((
10339                row_start..row_start,
10340                indent_delta.chars().collect::<String>(),
10341            ));
10342
10343            // Update this selection's endpoints to reflect the indentation.
10344            if row == selection.start.row {
10345                selection.start.column += indent_delta.len;
10346            }
10347            if row == selection.end.row {
10348                selection.end.column += indent_delta.len;
10349                delta_for_end_row = indent_delta.len;
10350            }
10351        }
10352
10353        if selection.start.row == selection.end.row {
10354            delta_for_start_row + delta_for_end_row
10355        } else {
10356            delta_for_end_row
10357        }
10358    }
10359
10360    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10361        if self.read_only(cx) {
10362            return;
10363        }
10364        if self.mode.is_single_line() {
10365            cx.propagate();
10366            return;
10367        }
10368
10369        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10370        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10371        let selections = self.selections.all::<Point>(cx);
10372        let mut deletion_ranges = Vec::new();
10373        let mut last_outdent = None;
10374        {
10375            let buffer = self.buffer.read(cx);
10376            let snapshot = buffer.snapshot(cx);
10377            for selection in &selections {
10378                let settings = buffer.language_settings_at(selection.start, cx);
10379                let tab_size = settings.tab_size.get();
10380                let mut rows = selection.spanned_rows(false, &display_map);
10381
10382                // Avoid re-outdenting a row that has already been outdented by a
10383                // previous selection.
10384                if let Some(last_row) = last_outdent
10385                    && last_row == rows.start
10386                {
10387                    rows.start = rows.start.next_row();
10388                }
10389                let has_multiple_rows = rows.len() > 1;
10390                for row in rows.iter_rows() {
10391                    let indent_size = snapshot.indent_size_for_line(row);
10392                    if indent_size.len > 0 {
10393                        let deletion_len = match indent_size.kind {
10394                            IndentKind::Space => {
10395                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10396                                if columns_to_prev_tab_stop == 0 {
10397                                    tab_size
10398                                } else {
10399                                    columns_to_prev_tab_stop
10400                                }
10401                            }
10402                            IndentKind::Tab => 1,
10403                        };
10404                        let start = if has_multiple_rows
10405                            || deletion_len > selection.start.column
10406                            || indent_size.len < selection.start.column
10407                        {
10408                            0
10409                        } else {
10410                            selection.start.column - deletion_len
10411                        };
10412                        deletion_ranges.push(
10413                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10414                        );
10415                        last_outdent = Some(row);
10416                    }
10417                }
10418            }
10419        }
10420
10421        self.transact(window, cx, |this, window, cx| {
10422            this.buffer.update(cx, |buffer, cx| {
10423                let empty_str: Arc<str> = Arc::default();
10424                buffer.edit(
10425                    deletion_ranges
10426                        .into_iter()
10427                        .map(|range| (range, empty_str.clone())),
10428                    None,
10429                    cx,
10430                );
10431            });
10432            let selections = this.selections.all::<usize>(cx);
10433            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10434        });
10435    }
10436
10437    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10438        if self.read_only(cx) {
10439            return;
10440        }
10441        if self.mode.is_single_line() {
10442            cx.propagate();
10443            return;
10444        }
10445
10446        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10447        let selections = self
10448            .selections
10449            .all::<usize>(cx)
10450            .into_iter()
10451            .map(|s| s.range());
10452
10453        self.transact(window, cx, |this, window, cx| {
10454            this.buffer.update(cx, |buffer, cx| {
10455                buffer.autoindent_ranges(selections, cx);
10456            });
10457            let selections = this.selections.all::<usize>(cx);
10458            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10459        });
10460    }
10461
10462    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10463        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10464        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10465        let selections = self.selections.all::<Point>(cx);
10466
10467        let mut new_cursors = Vec::new();
10468        let mut edit_ranges = Vec::new();
10469        let mut selections = selections.iter().peekable();
10470        while let Some(selection) = selections.next() {
10471            let mut rows = selection.spanned_rows(false, &display_map);
10472
10473            // Accumulate contiguous regions of rows that we want to delete.
10474            while let Some(next_selection) = selections.peek() {
10475                let next_rows = next_selection.spanned_rows(false, &display_map);
10476                if next_rows.start <= rows.end {
10477                    rows.end = next_rows.end;
10478                    selections.next().unwrap();
10479                } else {
10480                    break;
10481                }
10482            }
10483
10484            let buffer = display_map.buffer_snapshot();
10485            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10486            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10487                // If there's a line after the range, delete the \n from the end of the row range
10488                (
10489                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10490                    rows.end,
10491                )
10492            } else {
10493                // If there isn't a line after the range, delete the \n from the line before the
10494                // start of the row range
10495                edit_start = edit_start.saturating_sub(1);
10496                (buffer.len(), rows.start.previous_row())
10497            };
10498
10499            let text_layout_details = self.text_layout_details(window);
10500            let x = display_map.x_for_display_point(
10501                selection.head().to_display_point(&display_map),
10502                &text_layout_details,
10503            );
10504            let row = Point::new(target_row.0, 0)
10505                .to_display_point(&display_map)
10506                .row();
10507            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10508
10509            new_cursors.push((
10510                selection.id,
10511                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10512                SelectionGoal::None,
10513            ));
10514            edit_ranges.push(edit_start..edit_end);
10515        }
10516
10517        self.transact(window, cx, |this, window, cx| {
10518            let buffer = this.buffer.update(cx, |buffer, cx| {
10519                let empty_str: Arc<str> = Arc::default();
10520                buffer.edit(
10521                    edit_ranges
10522                        .into_iter()
10523                        .map(|range| (range, empty_str.clone())),
10524                    None,
10525                    cx,
10526                );
10527                buffer.snapshot(cx)
10528            });
10529            let new_selections = new_cursors
10530                .into_iter()
10531                .map(|(id, cursor, goal)| {
10532                    let cursor = cursor.to_point(&buffer);
10533                    Selection {
10534                        id,
10535                        start: cursor,
10536                        end: cursor,
10537                        reversed: false,
10538                        goal,
10539                    }
10540                })
10541                .collect();
10542
10543            this.change_selections(Default::default(), window, cx, |s| {
10544                s.select(new_selections);
10545            });
10546        });
10547    }
10548
10549    pub fn join_lines_impl(
10550        &mut self,
10551        insert_whitespace: bool,
10552        window: &mut Window,
10553        cx: &mut Context<Self>,
10554    ) {
10555        if self.read_only(cx) {
10556            return;
10557        }
10558        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10559        for selection in self.selections.all::<Point>(cx) {
10560            let start = MultiBufferRow(selection.start.row);
10561            // Treat single line selections as if they include the next line. Otherwise this action
10562            // would do nothing for single line selections individual cursors.
10563            let end = if selection.start.row == selection.end.row {
10564                MultiBufferRow(selection.start.row + 1)
10565            } else {
10566                MultiBufferRow(selection.end.row)
10567            };
10568
10569            if let Some(last_row_range) = row_ranges.last_mut()
10570                && start <= last_row_range.end
10571            {
10572                last_row_range.end = end;
10573                continue;
10574            }
10575            row_ranges.push(start..end);
10576        }
10577
10578        let snapshot = self.buffer.read(cx).snapshot(cx);
10579        let mut cursor_positions = Vec::new();
10580        for row_range in &row_ranges {
10581            let anchor = snapshot.anchor_before(Point::new(
10582                row_range.end.previous_row().0,
10583                snapshot.line_len(row_range.end.previous_row()),
10584            ));
10585            cursor_positions.push(anchor..anchor);
10586        }
10587
10588        self.transact(window, cx, |this, window, cx| {
10589            for row_range in row_ranges.into_iter().rev() {
10590                for row in row_range.iter_rows().rev() {
10591                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10592                    let next_line_row = row.next_row();
10593                    let indent = snapshot.indent_size_for_line(next_line_row);
10594                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10595
10596                    let replace =
10597                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10598                            " "
10599                        } else {
10600                            ""
10601                        };
10602
10603                    this.buffer.update(cx, |buffer, cx| {
10604                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10605                    });
10606                }
10607            }
10608
10609            this.change_selections(Default::default(), window, cx, |s| {
10610                s.select_anchor_ranges(cursor_positions)
10611            });
10612        });
10613    }
10614
10615    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10616        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10617        self.join_lines_impl(true, window, cx);
10618    }
10619
10620    pub fn sort_lines_case_sensitive(
10621        &mut self,
10622        _: &SortLinesCaseSensitive,
10623        window: &mut Window,
10624        cx: &mut Context<Self>,
10625    ) {
10626        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10627    }
10628
10629    pub fn sort_lines_by_length(
10630        &mut self,
10631        _: &SortLinesByLength,
10632        window: &mut Window,
10633        cx: &mut Context<Self>,
10634    ) {
10635        self.manipulate_immutable_lines(window, cx, |lines| {
10636            lines.sort_by_key(|&line| line.chars().count())
10637        })
10638    }
10639
10640    pub fn sort_lines_case_insensitive(
10641        &mut self,
10642        _: &SortLinesCaseInsensitive,
10643        window: &mut Window,
10644        cx: &mut Context<Self>,
10645    ) {
10646        self.manipulate_immutable_lines(window, cx, |lines| {
10647            lines.sort_by_key(|line| line.to_lowercase())
10648        })
10649    }
10650
10651    pub fn unique_lines_case_insensitive(
10652        &mut self,
10653        _: &UniqueLinesCaseInsensitive,
10654        window: &mut Window,
10655        cx: &mut Context<Self>,
10656    ) {
10657        self.manipulate_immutable_lines(window, cx, |lines| {
10658            let mut seen = HashSet::default();
10659            lines.retain(|line| seen.insert(line.to_lowercase()));
10660        })
10661    }
10662
10663    pub fn unique_lines_case_sensitive(
10664        &mut self,
10665        _: &UniqueLinesCaseSensitive,
10666        window: &mut Window,
10667        cx: &mut Context<Self>,
10668    ) {
10669        self.manipulate_immutable_lines(window, cx, |lines| {
10670            let mut seen = HashSet::default();
10671            lines.retain(|line| seen.insert(*line));
10672        })
10673    }
10674
10675    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10676        let snapshot = self.buffer.read(cx).snapshot(cx);
10677        for selection in self.selections.disjoint_anchors_arc().iter() {
10678            if snapshot
10679                .language_at(selection.start)
10680                .and_then(|lang| lang.config().wrap_characters.as_ref())
10681                .is_some()
10682            {
10683                return true;
10684            }
10685        }
10686        false
10687    }
10688
10689    fn wrap_selections_in_tag(
10690        &mut self,
10691        _: &WrapSelectionsInTag,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10696
10697        let snapshot = self.buffer.read(cx).snapshot(cx);
10698
10699        let mut edits = Vec::new();
10700        let mut boundaries = Vec::new();
10701
10702        for selection in self.selections.all::<Point>(cx).iter() {
10703            let Some(wrap_config) = snapshot
10704                .language_at(selection.start)
10705                .and_then(|lang| lang.config().wrap_characters.clone())
10706            else {
10707                continue;
10708            };
10709
10710            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10711            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10712
10713            let start_before = snapshot.anchor_before(selection.start);
10714            let end_after = snapshot.anchor_after(selection.end);
10715
10716            edits.push((start_before..start_before, open_tag));
10717            edits.push((end_after..end_after, close_tag));
10718
10719            boundaries.push((
10720                start_before,
10721                end_after,
10722                wrap_config.start_prefix.len(),
10723                wrap_config.end_suffix.len(),
10724            ));
10725        }
10726
10727        if edits.is_empty() {
10728            return;
10729        }
10730
10731        self.transact(window, cx, |this, window, cx| {
10732            let buffer = this.buffer.update(cx, |buffer, cx| {
10733                buffer.edit(edits, None, cx);
10734                buffer.snapshot(cx)
10735            });
10736
10737            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10738            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10739                boundaries.into_iter()
10740            {
10741                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10742                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10743                new_selections.push(open_offset..open_offset);
10744                new_selections.push(close_offset..close_offset);
10745            }
10746
10747            this.change_selections(Default::default(), window, cx, |s| {
10748                s.select_ranges(new_selections);
10749            });
10750
10751            this.request_autoscroll(Autoscroll::fit(), cx);
10752        });
10753    }
10754
10755    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10756        let Some(project) = self.project.clone() else {
10757            return;
10758        };
10759        self.reload(project, window, cx)
10760            .detach_and_notify_err(window, cx);
10761    }
10762
10763    pub fn restore_file(
10764        &mut self,
10765        _: &::git::RestoreFile,
10766        window: &mut Window,
10767        cx: &mut Context<Self>,
10768    ) {
10769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10770        let mut buffer_ids = HashSet::default();
10771        let snapshot = self.buffer().read(cx).snapshot(cx);
10772        for selection in self.selections.all::<usize>(cx) {
10773            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10774        }
10775
10776        let buffer = self.buffer().read(cx);
10777        let ranges = buffer_ids
10778            .into_iter()
10779            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10780            .collect::<Vec<_>>();
10781
10782        self.restore_hunks_in_ranges(ranges, window, cx);
10783    }
10784
10785    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10787        let selections = self
10788            .selections
10789            .all(cx)
10790            .into_iter()
10791            .map(|s| s.range())
10792            .collect();
10793        self.restore_hunks_in_ranges(selections, window, cx);
10794    }
10795
10796    pub fn restore_hunks_in_ranges(
10797        &mut self,
10798        ranges: Vec<Range<Point>>,
10799        window: &mut Window,
10800        cx: &mut Context<Editor>,
10801    ) {
10802        let mut revert_changes = HashMap::default();
10803        let chunk_by = self
10804            .snapshot(window, cx)
10805            .hunks_for_ranges(ranges)
10806            .into_iter()
10807            .chunk_by(|hunk| hunk.buffer_id);
10808        for (buffer_id, hunks) in &chunk_by {
10809            let hunks = hunks.collect::<Vec<_>>();
10810            for hunk in &hunks {
10811                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10812            }
10813            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10814        }
10815        drop(chunk_by);
10816        if !revert_changes.is_empty() {
10817            self.transact(window, cx, |editor, window, cx| {
10818                editor.restore(revert_changes, window, cx);
10819            });
10820        }
10821    }
10822
10823    pub fn open_active_item_in_terminal(
10824        &mut self,
10825        _: &OpenInTerminal,
10826        window: &mut Window,
10827        cx: &mut Context<Self>,
10828    ) {
10829        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10830            let project_path = buffer.read(cx).project_path(cx)?;
10831            let project = self.project()?.read(cx);
10832            let entry = project.entry_for_path(&project_path, cx)?;
10833            let parent = match &entry.canonical_path {
10834                Some(canonical_path) => canonical_path.to_path_buf(),
10835                None => project.absolute_path(&project_path, cx)?,
10836            }
10837            .parent()?
10838            .to_path_buf();
10839            Some(parent)
10840        }) {
10841            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10842        }
10843    }
10844
10845    fn set_breakpoint_context_menu(
10846        &mut self,
10847        display_row: DisplayRow,
10848        position: Option<Anchor>,
10849        clicked_point: gpui::Point<Pixels>,
10850        window: &mut Window,
10851        cx: &mut Context<Self>,
10852    ) {
10853        let source = self
10854            .buffer
10855            .read(cx)
10856            .snapshot(cx)
10857            .anchor_before(Point::new(display_row.0, 0u32));
10858
10859        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10860
10861        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10862            self,
10863            source,
10864            clicked_point,
10865            context_menu,
10866            window,
10867            cx,
10868        );
10869    }
10870
10871    fn add_edit_breakpoint_block(
10872        &mut self,
10873        anchor: Anchor,
10874        breakpoint: &Breakpoint,
10875        edit_action: BreakpointPromptEditAction,
10876        window: &mut Window,
10877        cx: &mut Context<Self>,
10878    ) {
10879        let weak_editor = cx.weak_entity();
10880        let bp_prompt = cx.new(|cx| {
10881            BreakpointPromptEditor::new(
10882                weak_editor,
10883                anchor,
10884                breakpoint.clone(),
10885                edit_action,
10886                window,
10887                cx,
10888            )
10889        });
10890
10891        let height = bp_prompt.update(cx, |this, cx| {
10892            this.prompt
10893                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10894        });
10895        let cloned_prompt = bp_prompt.clone();
10896        let blocks = vec![BlockProperties {
10897            style: BlockStyle::Sticky,
10898            placement: BlockPlacement::Above(anchor),
10899            height: Some(height),
10900            render: Arc::new(move |cx| {
10901                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10902                cloned_prompt.clone().into_any_element()
10903            }),
10904            priority: 0,
10905        }];
10906
10907        let focus_handle = bp_prompt.focus_handle(cx);
10908        window.focus(&focus_handle);
10909
10910        let block_ids = self.insert_blocks(blocks, None, cx);
10911        bp_prompt.update(cx, |prompt, _| {
10912            prompt.add_block_ids(block_ids);
10913        });
10914    }
10915
10916    pub(crate) fn breakpoint_at_row(
10917        &self,
10918        row: u32,
10919        window: &mut Window,
10920        cx: &mut Context<Self>,
10921    ) -> Option<(Anchor, Breakpoint)> {
10922        let snapshot = self.snapshot(window, cx);
10923        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10924
10925        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10926    }
10927
10928    pub(crate) fn breakpoint_at_anchor(
10929        &self,
10930        breakpoint_position: Anchor,
10931        snapshot: &EditorSnapshot,
10932        cx: &mut Context<Self>,
10933    ) -> Option<(Anchor, Breakpoint)> {
10934        let buffer = self
10935            .buffer
10936            .read(cx)
10937            .buffer_for_anchor(breakpoint_position, cx)?;
10938
10939        let enclosing_excerpt = breakpoint_position.excerpt_id;
10940        let buffer_snapshot = buffer.read(cx).snapshot();
10941
10942        let row = buffer_snapshot
10943            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10944            .row;
10945
10946        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10947        let anchor_end = snapshot
10948            .buffer_snapshot()
10949            .anchor_after(Point::new(row, line_len));
10950
10951        self.breakpoint_store
10952            .as_ref()?
10953            .read_with(cx, |breakpoint_store, cx| {
10954                breakpoint_store
10955                    .breakpoints(
10956                        &buffer,
10957                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10958                        &buffer_snapshot,
10959                        cx,
10960                    )
10961                    .next()
10962                    .and_then(|(bp, _)| {
10963                        let breakpoint_row = buffer_snapshot
10964                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10965                            .row;
10966
10967                        if breakpoint_row == row {
10968                            snapshot
10969                                .buffer_snapshot()
10970                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10971                                .map(|position| (position, bp.bp.clone()))
10972                        } else {
10973                            None
10974                        }
10975                    })
10976            })
10977    }
10978
10979    pub fn edit_log_breakpoint(
10980        &mut self,
10981        _: &EditLogBreakpoint,
10982        window: &mut Window,
10983        cx: &mut Context<Self>,
10984    ) {
10985        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10986            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10987                message: None,
10988                state: BreakpointState::Enabled,
10989                condition: None,
10990                hit_condition: None,
10991            });
10992
10993            self.add_edit_breakpoint_block(
10994                anchor,
10995                &breakpoint,
10996                BreakpointPromptEditAction::Log,
10997                window,
10998                cx,
10999            );
11000        }
11001    }
11002
11003    fn breakpoints_at_cursors(
11004        &self,
11005        window: &mut Window,
11006        cx: &mut Context<Self>,
11007    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11008        let snapshot = self.snapshot(window, cx);
11009        let cursors = self
11010            .selections
11011            .disjoint_anchors_arc()
11012            .iter()
11013            .map(|selection| {
11014                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11015
11016                let breakpoint_position = self
11017                    .breakpoint_at_row(cursor_position.row, window, cx)
11018                    .map(|bp| bp.0)
11019                    .unwrap_or_else(|| {
11020                        snapshot
11021                            .display_snapshot
11022                            .buffer_snapshot()
11023                            .anchor_after(Point::new(cursor_position.row, 0))
11024                    });
11025
11026                let breakpoint = self
11027                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11028                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11029
11030                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11031            })
11032            // 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.
11033            .collect::<HashMap<Anchor, _>>();
11034
11035        cursors.into_iter().collect()
11036    }
11037
11038    pub fn enable_breakpoint(
11039        &mut self,
11040        _: &crate::actions::EnableBreakpoint,
11041        window: &mut Window,
11042        cx: &mut Context<Self>,
11043    ) {
11044        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11045            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11046                continue;
11047            };
11048            self.edit_breakpoint_at_anchor(
11049                anchor,
11050                breakpoint,
11051                BreakpointEditAction::InvertState,
11052                cx,
11053            );
11054        }
11055    }
11056
11057    pub fn disable_breakpoint(
11058        &mut self,
11059        _: &crate::actions::DisableBreakpoint,
11060        window: &mut Window,
11061        cx: &mut Context<Self>,
11062    ) {
11063        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11064            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11065                continue;
11066            };
11067            self.edit_breakpoint_at_anchor(
11068                anchor,
11069                breakpoint,
11070                BreakpointEditAction::InvertState,
11071                cx,
11072            );
11073        }
11074    }
11075
11076    pub fn toggle_breakpoint(
11077        &mut self,
11078        _: &crate::actions::ToggleBreakpoint,
11079        window: &mut Window,
11080        cx: &mut Context<Self>,
11081    ) {
11082        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11083            if let Some(breakpoint) = breakpoint {
11084                self.edit_breakpoint_at_anchor(
11085                    anchor,
11086                    breakpoint,
11087                    BreakpointEditAction::Toggle,
11088                    cx,
11089                );
11090            } else {
11091                self.edit_breakpoint_at_anchor(
11092                    anchor,
11093                    Breakpoint::new_standard(),
11094                    BreakpointEditAction::Toggle,
11095                    cx,
11096                );
11097            }
11098        }
11099    }
11100
11101    pub fn edit_breakpoint_at_anchor(
11102        &mut self,
11103        breakpoint_position: Anchor,
11104        breakpoint: Breakpoint,
11105        edit_action: BreakpointEditAction,
11106        cx: &mut Context<Self>,
11107    ) {
11108        let Some(breakpoint_store) = &self.breakpoint_store else {
11109            return;
11110        };
11111
11112        let Some(buffer) = self
11113            .buffer
11114            .read(cx)
11115            .buffer_for_anchor(breakpoint_position, cx)
11116        else {
11117            return;
11118        };
11119
11120        breakpoint_store.update(cx, |breakpoint_store, cx| {
11121            breakpoint_store.toggle_breakpoint(
11122                buffer,
11123                BreakpointWithPosition {
11124                    position: breakpoint_position.text_anchor,
11125                    bp: breakpoint,
11126                },
11127                edit_action,
11128                cx,
11129            );
11130        });
11131
11132        cx.notify();
11133    }
11134
11135    #[cfg(any(test, feature = "test-support"))]
11136    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11137        self.breakpoint_store.clone()
11138    }
11139
11140    pub fn prepare_restore_change(
11141        &self,
11142        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11143        hunk: &MultiBufferDiffHunk,
11144        cx: &mut App,
11145    ) -> Option<()> {
11146        if hunk.is_created_file() {
11147            return None;
11148        }
11149        let buffer = self.buffer.read(cx);
11150        let diff = buffer.diff_for(hunk.buffer_id)?;
11151        let buffer = buffer.buffer(hunk.buffer_id)?;
11152        let buffer = buffer.read(cx);
11153        let original_text = diff
11154            .read(cx)
11155            .base_text()
11156            .as_rope()
11157            .slice(hunk.diff_base_byte_range.clone());
11158        let buffer_snapshot = buffer.snapshot();
11159        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11160        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11161            probe
11162                .0
11163                .start
11164                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11165                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11166        }) {
11167            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11168            Some(())
11169        } else {
11170            None
11171        }
11172    }
11173
11174    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11175        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11176    }
11177
11178    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11179        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11180    }
11181
11182    fn manipulate_lines<M>(
11183        &mut self,
11184        window: &mut Window,
11185        cx: &mut Context<Self>,
11186        mut manipulate: M,
11187    ) where
11188        M: FnMut(&str) -> LineManipulationResult,
11189    {
11190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11191
11192        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11193        let buffer = self.buffer.read(cx).snapshot(cx);
11194
11195        let mut edits = Vec::new();
11196
11197        let selections = self.selections.all::<Point>(cx);
11198        let mut selections = selections.iter().peekable();
11199        let mut contiguous_row_selections = Vec::new();
11200        let mut new_selections = Vec::new();
11201        let mut added_lines = 0;
11202        let mut removed_lines = 0;
11203
11204        while let Some(selection) = selections.next() {
11205            let (start_row, end_row) = consume_contiguous_rows(
11206                &mut contiguous_row_selections,
11207                selection,
11208                &display_map,
11209                &mut selections,
11210            );
11211
11212            let start_point = Point::new(start_row.0, 0);
11213            let end_point = Point::new(
11214                end_row.previous_row().0,
11215                buffer.line_len(end_row.previous_row()),
11216            );
11217            let text = buffer
11218                .text_for_range(start_point..end_point)
11219                .collect::<String>();
11220
11221            let LineManipulationResult {
11222                new_text,
11223                line_count_before,
11224                line_count_after,
11225            } = manipulate(&text);
11226
11227            edits.push((start_point..end_point, new_text));
11228
11229            // Selections must change based on added and removed line count
11230            let start_row =
11231                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11232            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11233            new_selections.push(Selection {
11234                id: selection.id,
11235                start: start_row,
11236                end: end_row,
11237                goal: SelectionGoal::None,
11238                reversed: selection.reversed,
11239            });
11240
11241            if line_count_after > line_count_before {
11242                added_lines += line_count_after - line_count_before;
11243            } else if line_count_before > line_count_after {
11244                removed_lines += line_count_before - line_count_after;
11245            }
11246        }
11247
11248        self.transact(window, cx, |this, window, cx| {
11249            let buffer = this.buffer.update(cx, |buffer, cx| {
11250                buffer.edit(edits, None, cx);
11251                buffer.snapshot(cx)
11252            });
11253
11254            // Recalculate offsets on newly edited buffer
11255            let new_selections = new_selections
11256                .iter()
11257                .map(|s| {
11258                    let start_point = Point::new(s.start.0, 0);
11259                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11260                    Selection {
11261                        id: s.id,
11262                        start: buffer.point_to_offset(start_point),
11263                        end: buffer.point_to_offset(end_point),
11264                        goal: s.goal,
11265                        reversed: s.reversed,
11266                    }
11267                })
11268                .collect();
11269
11270            this.change_selections(Default::default(), window, cx, |s| {
11271                s.select(new_selections);
11272            });
11273
11274            this.request_autoscroll(Autoscroll::fit(), cx);
11275        });
11276    }
11277
11278    fn manipulate_immutable_lines<Fn>(
11279        &mut self,
11280        window: &mut Window,
11281        cx: &mut Context<Self>,
11282        mut callback: Fn,
11283    ) where
11284        Fn: FnMut(&mut Vec<&str>),
11285    {
11286        self.manipulate_lines(window, cx, |text| {
11287            let mut lines: Vec<&str> = text.split('\n').collect();
11288            let line_count_before = lines.len();
11289
11290            callback(&mut lines);
11291
11292            LineManipulationResult {
11293                new_text: lines.join("\n"),
11294                line_count_before,
11295                line_count_after: lines.len(),
11296            }
11297        });
11298    }
11299
11300    fn manipulate_mutable_lines<Fn>(
11301        &mut self,
11302        window: &mut Window,
11303        cx: &mut Context<Self>,
11304        mut callback: Fn,
11305    ) where
11306        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11307    {
11308        self.manipulate_lines(window, cx, |text| {
11309            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11310            let line_count_before = lines.len();
11311
11312            callback(&mut lines);
11313
11314            LineManipulationResult {
11315                new_text: lines.join("\n"),
11316                line_count_before,
11317                line_count_after: lines.len(),
11318            }
11319        });
11320    }
11321
11322    pub fn convert_indentation_to_spaces(
11323        &mut self,
11324        _: &ConvertIndentationToSpaces,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        let settings = self.buffer.read(cx).language_settings(cx);
11329        let tab_size = settings.tab_size.get() as usize;
11330
11331        self.manipulate_mutable_lines(window, cx, |lines| {
11332            // Allocates a reasonably sized scratch buffer once for the whole loop
11333            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11334            // Avoids recomputing spaces that could be inserted many times
11335            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11336                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11337                .collect();
11338
11339            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11340                let mut chars = line.as_ref().chars();
11341                let mut col = 0;
11342                let mut changed = false;
11343
11344                for ch in chars.by_ref() {
11345                    match ch {
11346                        ' ' => {
11347                            reindented_line.push(' ');
11348                            col += 1;
11349                        }
11350                        '\t' => {
11351                            // \t are converted to spaces depending on the current column
11352                            let spaces_len = tab_size - (col % tab_size);
11353                            reindented_line.extend(&space_cache[spaces_len - 1]);
11354                            col += spaces_len;
11355                            changed = true;
11356                        }
11357                        _ => {
11358                            // If we dont append before break, the character is consumed
11359                            reindented_line.push(ch);
11360                            break;
11361                        }
11362                    }
11363                }
11364
11365                if !changed {
11366                    reindented_line.clear();
11367                    continue;
11368                }
11369                // Append the rest of the line and replace old reference with new one
11370                reindented_line.extend(chars);
11371                *line = Cow::Owned(reindented_line.clone());
11372                reindented_line.clear();
11373            }
11374        });
11375    }
11376
11377    pub fn convert_indentation_to_tabs(
11378        &mut self,
11379        _: &ConvertIndentationToTabs,
11380        window: &mut Window,
11381        cx: &mut Context<Self>,
11382    ) {
11383        let settings = self.buffer.read(cx).language_settings(cx);
11384        let tab_size = settings.tab_size.get() as usize;
11385
11386        self.manipulate_mutable_lines(window, cx, |lines| {
11387            // Allocates a reasonably sized buffer once for the whole loop
11388            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11389            // Avoids recomputing spaces that could be inserted many times
11390            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11391                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11392                .collect();
11393
11394            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11395                let mut chars = line.chars();
11396                let mut spaces_count = 0;
11397                let mut first_non_indent_char = None;
11398                let mut changed = false;
11399
11400                for ch in chars.by_ref() {
11401                    match ch {
11402                        ' ' => {
11403                            // Keep track of spaces. Append \t when we reach tab_size
11404                            spaces_count += 1;
11405                            changed = true;
11406                            if spaces_count == tab_size {
11407                                reindented_line.push('\t');
11408                                spaces_count = 0;
11409                            }
11410                        }
11411                        '\t' => {
11412                            reindented_line.push('\t');
11413                            spaces_count = 0;
11414                        }
11415                        _ => {
11416                            // Dont append it yet, we might have remaining spaces
11417                            first_non_indent_char = Some(ch);
11418                            break;
11419                        }
11420                    }
11421                }
11422
11423                if !changed {
11424                    reindented_line.clear();
11425                    continue;
11426                }
11427                // Remaining spaces that didn't make a full tab stop
11428                if spaces_count > 0 {
11429                    reindented_line.extend(&space_cache[spaces_count - 1]);
11430                }
11431                // If we consume an extra character that was not indentation, add it back
11432                if let Some(extra_char) = first_non_indent_char {
11433                    reindented_line.push(extra_char);
11434                }
11435                // Append the rest of the line and replace old reference with new one
11436                reindented_line.extend(chars);
11437                *line = Cow::Owned(reindented_line.clone());
11438                reindented_line.clear();
11439            }
11440        });
11441    }
11442
11443    pub fn convert_to_upper_case(
11444        &mut self,
11445        _: &ConvertToUpperCase,
11446        window: &mut Window,
11447        cx: &mut Context<Self>,
11448    ) {
11449        self.manipulate_text(window, cx, |text| text.to_uppercase())
11450    }
11451
11452    pub fn convert_to_lower_case(
11453        &mut self,
11454        _: &ConvertToLowerCase,
11455        window: &mut Window,
11456        cx: &mut Context<Self>,
11457    ) {
11458        self.manipulate_text(window, cx, |text| text.to_lowercase())
11459    }
11460
11461    pub fn convert_to_title_case(
11462        &mut self,
11463        _: &ConvertToTitleCase,
11464        window: &mut Window,
11465        cx: &mut Context<Self>,
11466    ) {
11467        self.manipulate_text(window, cx, |text| {
11468            text.split('\n')
11469                .map(|line| line.to_case(Case::Title))
11470                .join("\n")
11471        })
11472    }
11473
11474    pub fn convert_to_snake_case(
11475        &mut self,
11476        _: &ConvertToSnakeCase,
11477        window: &mut Window,
11478        cx: &mut Context<Self>,
11479    ) {
11480        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11481    }
11482
11483    pub fn convert_to_kebab_case(
11484        &mut self,
11485        _: &ConvertToKebabCase,
11486        window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11490    }
11491
11492    pub fn convert_to_upper_camel_case(
11493        &mut self,
11494        _: &ConvertToUpperCamelCase,
11495        window: &mut Window,
11496        cx: &mut Context<Self>,
11497    ) {
11498        self.manipulate_text(window, cx, |text| {
11499            text.split('\n')
11500                .map(|line| line.to_case(Case::UpperCamel))
11501                .join("\n")
11502        })
11503    }
11504
11505    pub fn convert_to_lower_camel_case(
11506        &mut self,
11507        _: &ConvertToLowerCamelCase,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11512    }
11513
11514    pub fn convert_to_opposite_case(
11515        &mut self,
11516        _: &ConvertToOppositeCase,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        self.manipulate_text(window, cx, |text| {
11521            text.chars()
11522                .fold(String::with_capacity(text.len()), |mut t, c| {
11523                    if c.is_uppercase() {
11524                        t.extend(c.to_lowercase());
11525                    } else {
11526                        t.extend(c.to_uppercase());
11527                    }
11528                    t
11529                })
11530        })
11531    }
11532
11533    pub fn convert_to_sentence_case(
11534        &mut self,
11535        _: &ConvertToSentenceCase,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11540    }
11541
11542    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11543        self.manipulate_text(window, cx, |text| {
11544            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11545            if has_upper_case_characters {
11546                text.to_lowercase()
11547            } else {
11548                text.to_uppercase()
11549            }
11550        })
11551    }
11552
11553    pub fn convert_to_rot13(
11554        &mut self,
11555        _: &ConvertToRot13,
11556        window: &mut Window,
11557        cx: &mut Context<Self>,
11558    ) {
11559        self.manipulate_text(window, cx, |text| {
11560            text.chars()
11561                .map(|c| match c {
11562                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11563                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11564                    _ => c,
11565                })
11566                .collect()
11567        })
11568    }
11569
11570    pub fn convert_to_rot47(
11571        &mut self,
11572        _: &ConvertToRot47,
11573        window: &mut Window,
11574        cx: &mut Context<Self>,
11575    ) {
11576        self.manipulate_text(window, cx, |text| {
11577            text.chars()
11578                .map(|c| {
11579                    let code_point = c as u32;
11580                    if code_point >= 33 && code_point <= 126 {
11581                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11582                    }
11583                    c
11584                })
11585                .collect()
11586        })
11587    }
11588
11589    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11590    where
11591        Fn: FnMut(&str) -> String,
11592    {
11593        let buffer = self.buffer.read(cx).snapshot(cx);
11594
11595        let mut new_selections = Vec::new();
11596        let mut edits = Vec::new();
11597        let mut selection_adjustment = 0i32;
11598
11599        for selection in self.selections.all_adjusted(cx) {
11600            let selection_is_empty = selection.is_empty();
11601
11602            let (start, end) = if selection_is_empty {
11603                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11604                (word_range.start, word_range.end)
11605            } else {
11606                (
11607                    buffer.point_to_offset(selection.start),
11608                    buffer.point_to_offset(selection.end),
11609                )
11610            };
11611
11612            let text = buffer.text_for_range(start..end).collect::<String>();
11613            let old_length = text.len() as i32;
11614            let text = callback(&text);
11615
11616            new_selections.push(Selection {
11617                start: (start as i32 - selection_adjustment) as usize,
11618                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11619                goal: SelectionGoal::None,
11620                id: selection.id,
11621                reversed: selection.reversed,
11622            });
11623
11624            selection_adjustment += old_length - text.len() as i32;
11625
11626            edits.push((start..end, text));
11627        }
11628
11629        self.transact(window, cx, |this, window, cx| {
11630            this.buffer.update(cx, |buffer, cx| {
11631                buffer.edit(edits, None, cx);
11632            });
11633
11634            this.change_selections(Default::default(), window, cx, |s| {
11635                s.select(new_selections);
11636            });
11637
11638            this.request_autoscroll(Autoscroll::fit(), cx);
11639        });
11640    }
11641
11642    pub fn move_selection_on_drop(
11643        &mut self,
11644        selection: &Selection<Anchor>,
11645        target: DisplayPoint,
11646        is_cut: bool,
11647        window: &mut Window,
11648        cx: &mut Context<Self>,
11649    ) {
11650        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11651        let buffer = display_map.buffer_snapshot();
11652        let mut edits = Vec::new();
11653        let insert_point = display_map
11654            .clip_point(target, Bias::Left)
11655            .to_point(&display_map);
11656        let text = buffer
11657            .text_for_range(selection.start..selection.end)
11658            .collect::<String>();
11659        if is_cut {
11660            edits.push(((selection.start..selection.end), String::new()));
11661        }
11662        let insert_anchor = buffer.anchor_before(insert_point);
11663        edits.push(((insert_anchor..insert_anchor), text));
11664        let last_edit_start = insert_anchor.bias_left(buffer);
11665        let last_edit_end = insert_anchor.bias_right(buffer);
11666        self.transact(window, cx, |this, window, cx| {
11667            this.buffer.update(cx, |buffer, cx| {
11668                buffer.edit(edits, None, cx);
11669            });
11670            this.change_selections(Default::default(), window, cx, |s| {
11671                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11672            });
11673        });
11674    }
11675
11676    pub fn clear_selection_drag_state(&mut self) {
11677        self.selection_drag_state = SelectionDragState::None;
11678    }
11679
11680    pub fn duplicate(
11681        &mut self,
11682        upwards: bool,
11683        whole_lines: bool,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11688
11689        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11690        let buffer = display_map.buffer_snapshot();
11691        let selections = self.selections.all::<Point>(cx);
11692
11693        let mut edits = Vec::new();
11694        let mut selections_iter = selections.iter().peekable();
11695        while let Some(selection) = selections_iter.next() {
11696            let mut rows = selection.spanned_rows(false, &display_map);
11697            // duplicate line-wise
11698            if whole_lines || selection.start == selection.end {
11699                // Avoid duplicating the same lines twice.
11700                while let Some(next_selection) = selections_iter.peek() {
11701                    let next_rows = next_selection.spanned_rows(false, &display_map);
11702                    if next_rows.start < rows.end {
11703                        rows.end = next_rows.end;
11704                        selections_iter.next().unwrap();
11705                    } else {
11706                        break;
11707                    }
11708                }
11709
11710                // Copy the text from the selected row region and splice it either at the start
11711                // or end of the region.
11712                let start = Point::new(rows.start.0, 0);
11713                let end = Point::new(
11714                    rows.end.previous_row().0,
11715                    buffer.line_len(rows.end.previous_row()),
11716                );
11717
11718                let mut text = buffer.text_for_range(start..end).collect::<String>();
11719
11720                let insert_location = if upwards {
11721                    // When duplicating upward, we need to insert before the current line.
11722                    // If we're on the last line and it doesn't end with a newline,
11723                    // we need to add a newline before the duplicated content.
11724                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11725                        && buffer.max_point().column > 0
11726                        && !text.ends_with('\n');
11727
11728                    if needs_leading_newline {
11729                        text.insert(0, '\n');
11730                        end
11731                    } else {
11732                        text.push('\n');
11733                        Point::new(rows.end.0, 0)
11734                    }
11735                } else {
11736                    text.push('\n');
11737                    start
11738                };
11739                edits.push((insert_location..insert_location, text));
11740            } else {
11741                // duplicate character-wise
11742                let start = selection.start;
11743                let end = selection.end;
11744                let text = buffer.text_for_range(start..end).collect::<String>();
11745                edits.push((selection.end..selection.end, text));
11746            }
11747        }
11748
11749        self.transact(window, cx, |this, _, cx| {
11750            this.buffer.update(cx, |buffer, cx| {
11751                buffer.edit(edits, None, cx);
11752            });
11753
11754            this.request_autoscroll(Autoscroll::fit(), cx);
11755        });
11756    }
11757
11758    pub fn duplicate_line_up(
11759        &mut self,
11760        _: &DuplicateLineUp,
11761        window: &mut Window,
11762        cx: &mut Context<Self>,
11763    ) {
11764        self.duplicate(true, true, window, cx);
11765    }
11766
11767    pub fn duplicate_line_down(
11768        &mut self,
11769        _: &DuplicateLineDown,
11770        window: &mut Window,
11771        cx: &mut Context<Self>,
11772    ) {
11773        self.duplicate(false, true, window, cx);
11774    }
11775
11776    pub fn duplicate_selection(
11777        &mut self,
11778        _: &DuplicateSelection,
11779        window: &mut Window,
11780        cx: &mut Context<Self>,
11781    ) {
11782        self.duplicate(false, false, window, cx);
11783    }
11784
11785    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11787        if self.mode.is_single_line() {
11788            cx.propagate();
11789            return;
11790        }
11791
11792        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11793        let buffer = self.buffer.read(cx).snapshot(cx);
11794
11795        let mut edits = Vec::new();
11796        let mut unfold_ranges = Vec::new();
11797        let mut refold_creases = Vec::new();
11798
11799        let selections = self.selections.all::<Point>(cx);
11800        let mut selections = selections.iter().peekable();
11801        let mut contiguous_row_selections = Vec::new();
11802        let mut new_selections = Vec::new();
11803
11804        while let Some(selection) = selections.next() {
11805            // Find all the selections that span a contiguous row range
11806            let (start_row, end_row) = consume_contiguous_rows(
11807                &mut contiguous_row_selections,
11808                selection,
11809                &display_map,
11810                &mut selections,
11811            );
11812
11813            // Move the text spanned by the row range to be before the line preceding the row range
11814            if start_row.0 > 0 {
11815                let range_to_move = Point::new(
11816                    start_row.previous_row().0,
11817                    buffer.line_len(start_row.previous_row()),
11818                )
11819                    ..Point::new(
11820                        end_row.previous_row().0,
11821                        buffer.line_len(end_row.previous_row()),
11822                    );
11823                let insertion_point = display_map
11824                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11825                    .0;
11826
11827                // Don't move lines across excerpts
11828                if buffer
11829                    .excerpt_containing(insertion_point..range_to_move.end)
11830                    .is_some()
11831                {
11832                    let text = buffer
11833                        .text_for_range(range_to_move.clone())
11834                        .flat_map(|s| s.chars())
11835                        .skip(1)
11836                        .chain(['\n'])
11837                        .collect::<String>();
11838
11839                    edits.push((
11840                        buffer.anchor_after(range_to_move.start)
11841                            ..buffer.anchor_before(range_to_move.end),
11842                        String::new(),
11843                    ));
11844                    let insertion_anchor = buffer.anchor_after(insertion_point);
11845                    edits.push((insertion_anchor..insertion_anchor, text));
11846
11847                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11848
11849                    // Move selections up
11850                    new_selections.extend(contiguous_row_selections.drain(..).map(
11851                        |mut selection| {
11852                            selection.start.row -= row_delta;
11853                            selection.end.row -= row_delta;
11854                            selection
11855                        },
11856                    ));
11857
11858                    // Move folds up
11859                    unfold_ranges.push(range_to_move.clone());
11860                    for fold in display_map.folds_in_range(
11861                        buffer.anchor_before(range_to_move.start)
11862                            ..buffer.anchor_after(range_to_move.end),
11863                    ) {
11864                        let mut start = fold.range.start.to_point(&buffer);
11865                        let mut end = fold.range.end.to_point(&buffer);
11866                        start.row -= row_delta;
11867                        end.row -= row_delta;
11868                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11869                    }
11870                }
11871            }
11872
11873            // If we didn't move line(s), preserve the existing selections
11874            new_selections.append(&mut contiguous_row_selections);
11875        }
11876
11877        self.transact(window, cx, |this, window, cx| {
11878            this.unfold_ranges(&unfold_ranges, true, true, cx);
11879            this.buffer.update(cx, |buffer, cx| {
11880                for (range, text) in edits {
11881                    buffer.edit([(range, text)], None, cx);
11882                }
11883            });
11884            this.fold_creases(refold_creases, true, window, cx);
11885            this.change_selections(Default::default(), window, cx, |s| {
11886                s.select(new_selections);
11887            })
11888        });
11889    }
11890
11891    pub fn move_line_down(
11892        &mut self,
11893        _: &MoveLineDown,
11894        window: &mut Window,
11895        cx: &mut Context<Self>,
11896    ) {
11897        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11898        if self.mode.is_single_line() {
11899            cx.propagate();
11900            return;
11901        }
11902
11903        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11904        let buffer = self.buffer.read(cx).snapshot(cx);
11905
11906        let mut edits = Vec::new();
11907        let mut unfold_ranges = Vec::new();
11908        let mut refold_creases = Vec::new();
11909
11910        let selections = self.selections.all::<Point>(cx);
11911        let mut selections = selections.iter().peekable();
11912        let mut contiguous_row_selections = Vec::new();
11913        let mut new_selections = Vec::new();
11914
11915        while let Some(selection) = selections.next() {
11916            // Find all the selections that span a contiguous row range
11917            let (start_row, end_row) = consume_contiguous_rows(
11918                &mut contiguous_row_selections,
11919                selection,
11920                &display_map,
11921                &mut selections,
11922            );
11923
11924            // Move the text spanned by the row range to be after the last line of the row range
11925            if end_row.0 <= buffer.max_point().row {
11926                let range_to_move =
11927                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11928                let insertion_point = display_map
11929                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11930                    .0;
11931
11932                // Don't move lines across excerpt boundaries
11933                if buffer
11934                    .excerpt_containing(range_to_move.start..insertion_point)
11935                    .is_some()
11936                {
11937                    let mut text = String::from("\n");
11938                    text.extend(buffer.text_for_range(range_to_move.clone()));
11939                    text.pop(); // Drop trailing newline
11940                    edits.push((
11941                        buffer.anchor_after(range_to_move.start)
11942                            ..buffer.anchor_before(range_to_move.end),
11943                        String::new(),
11944                    ));
11945                    let insertion_anchor = buffer.anchor_after(insertion_point);
11946                    edits.push((insertion_anchor..insertion_anchor, text));
11947
11948                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11949
11950                    // Move selections down
11951                    new_selections.extend(contiguous_row_selections.drain(..).map(
11952                        |mut selection| {
11953                            selection.start.row += row_delta;
11954                            selection.end.row += row_delta;
11955                            selection
11956                        },
11957                    ));
11958
11959                    // Move folds down
11960                    unfold_ranges.push(range_to_move.clone());
11961                    for fold in display_map.folds_in_range(
11962                        buffer.anchor_before(range_to_move.start)
11963                            ..buffer.anchor_after(range_to_move.end),
11964                    ) {
11965                        let mut start = fold.range.start.to_point(&buffer);
11966                        let mut end = fold.range.end.to_point(&buffer);
11967                        start.row += row_delta;
11968                        end.row += row_delta;
11969                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11970                    }
11971                }
11972            }
11973
11974            // If we didn't move line(s), preserve the existing selections
11975            new_selections.append(&mut contiguous_row_selections);
11976        }
11977
11978        self.transact(window, cx, |this, window, cx| {
11979            this.unfold_ranges(&unfold_ranges, true, true, cx);
11980            this.buffer.update(cx, |buffer, cx| {
11981                for (range, text) in edits {
11982                    buffer.edit([(range, text)], None, cx);
11983                }
11984            });
11985            this.fold_creases(refold_creases, true, window, cx);
11986            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11987        });
11988    }
11989
11990    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11992        let text_layout_details = &self.text_layout_details(window);
11993        self.transact(window, cx, |this, window, cx| {
11994            let edits = this.change_selections(Default::default(), window, cx, |s| {
11995                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11996                s.move_with(|display_map, selection| {
11997                    if !selection.is_empty() {
11998                        return;
11999                    }
12000
12001                    let mut head = selection.head();
12002                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12003                    if head.column() == display_map.line_len(head.row()) {
12004                        transpose_offset = display_map
12005                            .buffer_snapshot()
12006                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12007                    }
12008
12009                    if transpose_offset == 0 {
12010                        return;
12011                    }
12012
12013                    *head.column_mut() += 1;
12014                    head = display_map.clip_point(head, Bias::Right);
12015                    let goal = SelectionGoal::HorizontalPosition(
12016                        display_map
12017                            .x_for_display_point(head, text_layout_details)
12018                            .into(),
12019                    );
12020                    selection.collapse_to(head, goal);
12021
12022                    let transpose_start = display_map
12023                        .buffer_snapshot()
12024                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12025                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12026                        let transpose_end = display_map
12027                            .buffer_snapshot()
12028                            .clip_offset(transpose_offset + 1, Bias::Right);
12029                        if let Some(ch) = display_map
12030                            .buffer_snapshot()
12031                            .chars_at(transpose_start)
12032                            .next()
12033                        {
12034                            edits.push((transpose_start..transpose_offset, String::new()));
12035                            edits.push((transpose_end..transpose_end, ch.to_string()));
12036                        }
12037                    }
12038                });
12039                edits
12040            });
12041            this.buffer
12042                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12043            let selections = this.selections.all::<usize>(cx);
12044            this.change_selections(Default::default(), window, cx, |s| {
12045                s.select(selections);
12046            });
12047        });
12048    }
12049
12050    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12052        if self.mode.is_single_line() {
12053            cx.propagate();
12054            return;
12055        }
12056
12057        self.rewrap_impl(RewrapOptions::default(), cx)
12058    }
12059
12060    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12061        let buffer = self.buffer.read(cx).snapshot(cx);
12062        let selections = self.selections.all::<Point>(cx);
12063
12064        #[derive(Clone, Debug, PartialEq)]
12065        enum CommentFormat {
12066            /// single line comment, with prefix for line
12067            Line(String),
12068            /// single line within a block comment, with prefix for line
12069            BlockLine(String),
12070            /// a single line of a block comment that includes the initial delimiter
12071            BlockCommentWithStart(BlockCommentConfig),
12072            /// a single line of a block comment that includes the ending delimiter
12073            BlockCommentWithEnd(BlockCommentConfig),
12074        }
12075
12076        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12077        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12078            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12079                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12080                .peekable();
12081
12082            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12083                row
12084            } else {
12085                return Vec::new();
12086            };
12087
12088            let language_settings = buffer.language_settings_at(selection.head(), cx);
12089            let language_scope = buffer.language_scope_at(selection.head());
12090
12091            let indent_and_prefix_for_row =
12092                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12093                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12094                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12095                        &language_scope
12096                    {
12097                        let indent_end = Point::new(row, indent.len);
12098                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12099                        let line_text_after_indent = buffer
12100                            .text_for_range(indent_end..line_end)
12101                            .collect::<String>();
12102
12103                        let is_within_comment_override = buffer
12104                            .language_scope_at(indent_end)
12105                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12106                        let comment_delimiters = if is_within_comment_override {
12107                            // we are within a comment syntax node, but we don't
12108                            // yet know what kind of comment: block, doc or line
12109                            match (
12110                                language_scope.documentation_comment(),
12111                                language_scope.block_comment(),
12112                            ) {
12113                                (Some(config), _) | (_, Some(config))
12114                                    if buffer.contains_str_at(indent_end, &config.start) =>
12115                                {
12116                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12117                                }
12118                                (Some(config), _) | (_, Some(config))
12119                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12120                                {
12121                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12122                                }
12123                                (Some(config), _) | (_, Some(config))
12124                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12125                                {
12126                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12127                                }
12128                                (_, _) => language_scope
12129                                    .line_comment_prefixes()
12130                                    .iter()
12131                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12132                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12133                            }
12134                        } else {
12135                            // we not in an overridden comment node, but we may
12136                            // be within a non-overridden line comment node
12137                            language_scope
12138                                .line_comment_prefixes()
12139                                .iter()
12140                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12141                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12142                        };
12143
12144                        let rewrap_prefix = language_scope
12145                            .rewrap_prefixes()
12146                            .iter()
12147                            .find_map(|prefix_regex| {
12148                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12149                                    if mat.start() == 0 {
12150                                        Some(mat.as_str().to_string())
12151                                    } else {
12152                                        None
12153                                    }
12154                                })
12155                            })
12156                            .flatten();
12157                        (comment_delimiters, rewrap_prefix)
12158                    } else {
12159                        (None, None)
12160                    };
12161                    (indent, comment_prefix, rewrap_prefix)
12162                };
12163
12164            let mut ranges = Vec::new();
12165            let from_empty_selection = selection.is_empty();
12166
12167            let mut current_range_start = first_row;
12168            let mut prev_row = first_row;
12169            let (
12170                mut current_range_indent,
12171                mut current_range_comment_delimiters,
12172                mut current_range_rewrap_prefix,
12173            ) = indent_and_prefix_for_row(first_row);
12174
12175            for row in non_blank_rows_iter.skip(1) {
12176                let has_paragraph_break = row > prev_row + 1;
12177
12178                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12179                    indent_and_prefix_for_row(row);
12180
12181                let has_indent_change = row_indent != current_range_indent;
12182                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12183
12184                let has_boundary_change = has_comment_change
12185                    || row_rewrap_prefix.is_some()
12186                    || (has_indent_change && current_range_comment_delimiters.is_some());
12187
12188                if has_paragraph_break || has_boundary_change {
12189                    ranges.push((
12190                        language_settings.clone(),
12191                        Point::new(current_range_start, 0)
12192                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12193                        current_range_indent,
12194                        current_range_comment_delimiters.clone(),
12195                        current_range_rewrap_prefix.clone(),
12196                        from_empty_selection,
12197                    ));
12198                    current_range_start = row;
12199                    current_range_indent = row_indent;
12200                    current_range_comment_delimiters = row_comment_delimiters;
12201                    current_range_rewrap_prefix = row_rewrap_prefix;
12202                }
12203                prev_row = row;
12204            }
12205
12206            ranges.push((
12207                language_settings.clone(),
12208                Point::new(current_range_start, 0)
12209                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12210                current_range_indent,
12211                current_range_comment_delimiters,
12212                current_range_rewrap_prefix,
12213                from_empty_selection,
12214            ));
12215
12216            ranges
12217        });
12218
12219        let mut edits = Vec::new();
12220        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12221
12222        for (
12223            language_settings,
12224            wrap_range,
12225            mut indent_size,
12226            comment_prefix,
12227            rewrap_prefix,
12228            from_empty_selection,
12229        ) in wrap_ranges
12230        {
12231            let mut start_row = wrap_range.start.row;
12232            let mut end_row = wrap_range.end.row;
12233
12234            // Skip selections that overlap with a range that has already been rewrapped.
12235            let selection_range = start_row..end_row;
12236            if rewrapped_row_ranges
12237                .iter()
12238                .any(|range| range.overlaps(&selection_range))
12239            {
12240                continue;
12241            }
12242
12243            let tab_size = language_settings.tab_size;
12244
12245            let (line_prefix, inside_comment) = match &comment_prefix {
12246                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12247                    (Some(prefix.as_str()), true)
12248                }
12249                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12250                    (Some(prefix.as_ref()), true)
12251                }
12252                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12253                    start: _,
12254                    end: _,
12255                    prefix,
12256                    tab_size,
12257                })) => {
12258                    indent_size.len += tab_size;
12259                    (Some(prefix.as_ref()), true)
12260                }
12261                None => (None, false),
12262            };
12263            let indent_prefix = indent_size.chars().collect::<String>();
12264            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12265
12266            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12267                RewrapBehavior::InComments => inside_comment,
12268                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12269                RewrapBehavior::Anywhere => true,
12270            };
12271
12272            let should_rewrap = options.override_language_settings
12273                || allow_rewrap_based_on_language
12274                || self.hard_wrap.is_some();
12275            if !should_rewrap {
12276                continue;
12277            }
12278
12279            if from_empty_selection {
12280                'expand_upwards: while start_row > 0 {
12281                    let prev_row = start_row - 1;
12282                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12283                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12284                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12285                    {
12286                        start_row = prev_row;
12287                    } else {
12288                        break 'expand_upwards;
12289                    }
12290                }
12291
12292                'expand_downwards: while end_row < buffer.max_point().row {
12293                    let next_row = end_row + 1;
12294                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12295                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12296                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12297                    {
12298                        end_row = next_row;
12299                    } else {
12300                        break 'expand_downwards;
12301                    }
12302                }
12303            }
12304
12305            let start = Point::new(start_row, 0);
12306            let start_offset = ToOffset::to_offset(&start, &buffer);
12307            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12308            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12309            let mut first_line_delimiter = None;
12310            let mut last_line_delimiter = None;
12311            let Some(lines_without_prefixes) = selection_text
12312                .lines()
12313                .enumerate()
12314                .map(|(ix, line)| {
12315                    let line_trimmed = line.trim_start();
12316                    if rewrap_prefix.is_some() && ix > 0 {
12317                        Ok(line_trimmed)
12318                    } else if let Some(
12319                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12320                            start,
12321                            prefix,
12322                            end,
12323                            tab_size,
12324                        })
12325                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12326                            start,
12327                            prefix,
12328                            end,
12329                            tab_size,
12330                        }),
12331                    ) = &comment_prefix
12332                    {
12333                        let line_trimmed = line_trimmed
12334                            .strip_prefix(start.as_ref())
12335                            .map(|s| {
12336                                let mut indent_size = indent_size;
12337                                indent_size.len -= tab_size;
12338                                let indent_prefix: String = indent_size.chars().collect();
12339                                first_line_delimiter = Some((indent_prefix, start));
12340                                s.trim_start()
12341                            })
12342                            .unwrap_or(line_trimmed);
12343                        let line_trimmed = line_trimmed
12344                            .strip_suffix(end.as_ref())
12345                            .map(|s| {
12346                                last_line_delimiter = Some(end);
12347                                s.trim_end()
12348                            })
12349                            .unwrap_or(line_trimmed);
12350                        let line_trimmed = line_trimmed
12351                            .strip_prefix(prefix.as_ref())
12352                            .unwrap_or(line_trimmed);
12353                        Ok(line_trimmed)
12354                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12355                        line_trimmed.strip_prefix(prefix).with_context(|| {
12356                            format!("line did not start with prefix {prefix:?}: {line:?}")
12357                        })
12358                    } else {
12359                        line_trimmed
12360                            .strip_prefix(&line_prefix.trim_start())
12361                            .with_context(|| {
12362                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12363                            })
12364                    }
12365                })
12366                .collect::<Result<Vec<_>, _>>()
12367                .log_err()
12368            else {
12369                continue;
12370            };
12371
12372            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12373                buffer
12374                    .language_settings_at(Point::new(start_row, 0), cx)
12375                    .preferred_line_length as usize
12376            });
12377
12378            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12379                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12380            } else {
12381                line_prefix.clone()
12382            };
12383
12384            let wrapped_text = {
12385                let mut wrapped_text = wrap_with_prefix(
12386                    line_prefix,
12387                    subsequent_lines_prefix,
12388                    lines_without_prefixes.join("\n"),
12389                    wrap_column,
12390                    tab_size,
12391                    options.preserve_existing_whitespace,
12392                );
12393
12394                if let Some((indent, delimiter)) = first_line_delimiter {
12395                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12396                }
12397                if let Some(last_line) = last_line_delimiter {
12398                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12399                }
12400
12401                wrapped_text
12402            };
12403
12404            // TODO: should always use char-based diff while still supporting cursor behavior that
12405            // matches vim.
12406            let mut diff_options = DiffOptions::default();
12407            if options.override_language_settings {
12408                diff_options.max_word_diff_len = 0;
12409                diff_options.max_word_diff_line_count = 0;
12410            } else {
12411                diff_options.max_word_diff_len = usize::MAX;
12412                diff_options.max_word_diff_line_count = usize::MAX;
12413            }
12414
12415            for (old_range, new_text) in
12416                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12417            {
12418                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12419                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12420                edits.push((edit_start..edit_end, new_text));
12421            }
12422
12423            rewrapped_row_ranges.push(start_row..=end_row);
12424        }
12425
12426        self.buffer
12427            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12428    }
12429
12430    pub fn cut_common(
12431        &mut self,
12432        cut_no_selection_line: bool,
12433        window: &mut Window,
12434        cx: &mut Context<Self>,
12435    ) -> ClipboardItem {
12436        let mut text = String::new();
12437        let buffer = self.buffer.read(cx).snapshot(cx);
12438        let mut selections = self.selections.all::<Point>(cx);
12439        let mut clipboard_selections = Vec::with_capacity(selections.len());
12440        {
12441            let max_point = buffer.max_point();
12442            let mut is_first = true;
12443            for selection in &mut selections {
12444                let is_entire_line =
12445                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12446                if is_entire_line {
12447                    selection.start = Point::new(selection.start.row, 0);
12448                    if !selection.is_empty() && selection.end.column == 0 {
12449                        selection.end = cmp::min(max_point, selection.end);
12450                    } else {
12451                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12452                    }
12453                    selection.goal = SelectionGoal::None;
12454                }
12455                if is_first {
12456                    is_first = false;
12457                } else {
12458                    text += "\n";
12459                }
12460                let mut len = 0;
12461                for chunk in buffer.text_for_range(selection.start..selection.end) {
12462                    text.push_str(chunk);
12463                    len += chunk.len();
12464                }
12465                clipboard_selections.push(ClipboardSelection {
12466                    len,
12467                    is_entire_line,
12468                    first_line_indent: buffer
12469                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12470                        .len,
12471                });
12472            }
12473        }
12474
12475        self.transact(window, cx, |this, window, cx| {
12476            this.change_selections(Default::default(), window, cx, |s| {
12477                s.select(selections);
12478            });
12479            this.insert("", window, cx);
12480        });
12481        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12482    }
12483
12484    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12486        let item = self.cut_common(true, window, cx);
12487        cx.write_to_clipboard(item);
12488    }
12489
12490    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12491        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12492        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12493            s.move_with(|snapshot, sel| {
12494                if sel.is_empty() {
12495                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12496                }
12497                if sel.is_empty() {
12498                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12499                }
12500            });
12501        });
12502        let item = self.cut_common(false, window, cx);
12503        cx.set_global(KillRing(item))
12504    }
12505
12506    pub fn kill_ring_yank(
12507        &mut self,
12508        _: &KillRingYank,
12509        window: &mut Window,
12510        cx: &mut Context<Self>,
12511    ) {
12512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12513        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12514            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12515                (kill_ring.text().to_string(), kill_ring.metadata_json())
12516            } else {
12517                return;
12518            }
12519        } else {
12520            return;
12521        };
12522        self.do_paste(&text, metadata, false, window, cx);
12523    }
12524
12525    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12526        self.do_copy(true, cx);
12527    }
12528
12529    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12530        self.do_copy(false, cx);
12531    }
12532
12533    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12534        let selections = self.selections.all::<Point>(cx);
12535        let buffer = self.buffer.read(cx).read(cx);
12536        let mut text = String::new();
12537
12538        let mut clipboard_selections = Vec::with_capacity(selections.len());
12539        {
12540            let max_point = buffer.max_point();
12541            let mut is_first = true;
12542            for selection in &selections {
12543                let mut start = selection.start;
12544                let mut end = selection.end;
12545                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12546                let mut add_trailing_newline = false;
12547                if is_entire_line {
12548                    start = Point::new(start.row, 0);
12549                    let next_line_start = Point::new(end.row + 1, 0);
12550                    if next_line_start <= max_point {
12551                        end = next_line_start;
12552                    } else {
12553                        // We're on the last line without a trailing newline.
12554                        // Copy to the end of the line and add a newline afterwards.
12555                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12556                        add_trailing_newline = true;
12557                    }
12558                }
12559
12560                let mut trimmed_selections = Vec::new();
12561                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12562                    let row = MultiBufferRow(start.row);
12563                    let first_indent = buffer.indent_size_for_line(row);
12564                    if first_indent.len == 0 || start.column > first_indent.len {
12565                        trimmed_selections.push(start..end);
12566                    } else {
12567                        trimmed_selections.push(
12568                            Point::new(row.0, first_indent.len)
12569                                ..Point::new(row.0, buffer.line_len(row)),
12570                        );
12571                        for row in start.row + 1..=end.row {
12572                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12573                            if row == end.row {
12574                                line_len = end.column;
12575                            }
12576                            if line_len == 0 {
12577                                trimmed_selections
12578                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12579                                continue;
12580                            }
12581                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12582                            if row_indent_size.len >= first_indent.len {
12583                                trimmed_selections.push(
12584                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12585                                );
12586                            } else {
12587                                trimmed_selections.clear();
12588                                trimmed_selections.push(start..end);
12589                                break;
12590                            }
12591                        }
12592                    }
12593                } else {
12594                    trimmed_selections.push(start..end);
12595                }
12596
12597                for trimmed_range in trimmed_selections {
12598                    if is_first {
12599                        is_first = false;
12600                    } else {
12601                        text += "\n";
12602                    }
12603                    let mut len = 0;
12604                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12605                        text.push_str(chunk);
12606                        len += chunk.len();
12607                    }
12608                    if add_trailing_newline {
12609                        text.push('\n');
12610                        len += 1;
12611                    }
12612                    clipboard_selections.push(ClipboardSelection {
12613                        len,
12614                        is_entire_line,
12615                        first_line_indent: buffer
12616                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12617                            .len,
12618                    });
12619                }
12620            }
12621        }
12622
12623        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12624            text,
12625            clipboard_selections,
12626        ));
12627    }
12628
12629    pub fn do_paste(
12630        &mut self,
12631        text: &String,
12632        clipboard_selections: Option<Vec<ClipboardSelection>>,
12633        handle_entire_lines: bool,
12634        window: &mut Window,
12635        cx: &mut Context<Self>,
12636    ) {
12637        if self.read_only(cx) {
12638            return;
12639        }
12640
12641        let clipboard_text = Cow::Borrowed(text.as_str());
12642
12643        self.transact(window, cx, |this, window, cx| {
12644            let had_active_edit_prediction = this.has_active_edit_prediction();
12645            let old_selections = this.selections.all::<usize>(cx);
12646            let cursor_offset = this.selections.last::<usize>(cx).head();
12647
12648            if let Some(mut clipboard_selections) = clipboard_selections {
12649                let all_selections_were_entire_line =
12650                    clipboard_selections.iter().all(|s| s.is_entire_line);
12651                let first_selection_indent_column =
12652                    clipboard_selections.first().map(|s| s.first_line_indent);
12653                if clipboard_selections.len() != old_selections.len() {
12654                    clipboard_selections.drain(..);
12655                }
12656                let mut auto_indent_on_paste = true;
12657
12658                this.buffer.update(cx, |buffer, cx| {
12659                    let snapshot = buffer.read(cx);
12660                    auto_indent_on_paste = snapshot
12661                        .language_settings_at(cursor_offset, cx)
12662                        .auto_indent_on_paste;
12663
12664                    let mut start_offset = 0;
12665                    let mut edits = Vec::new();
12666                    let mut original_indent_columns = Vec::new();
12667                    for (ix, selection) in old_selections.iter().enumerate() {
12668                        let to_insert;
12669                        let entire_line;
12670                        let original_indent_column;
12671                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12672                            let end_offset = start_offset + clipboard_selection.len;
12673                            to_insert = &clipboard_text[start_offset..end_offset];
12674                            entire_line = clipboard_selection.is_entire_line;
12675                            start_offset = end_offset + 1;
12676                            original_indent_column = Some(clipboard_selection.first_line_indent);
12677                        } else {
12678                            to_insert = &*clipboard_text;
12679                            entire_line = all_selections_were_entire_line;
12680                            original_indent_column = first_selection_indent_column
12681                        }
12682
12683                        let (range, to_insert) =
12684                            if selection.is_empty() && handle_entire_lines && entire_line {
12685                                // If the corresponding selection was empty when this slice of the
12686                                // clipboard text was written, then the entire line containing the
12687                                // selection was copied. If this selection is also currently empty,
12688                                // then paste the line before the current line of the buffer.
12689                                let column = selection.start.to_point(&snapshot).column as usize;
12690                                let line_start = selection.start - column;
12691                                (line_start..line_start, Cow::Borrowed(to_insert))
12692                            } else {
12693                                let language = snapshot.language_at(selection.head());
12694                                let range = selection.range();
12695                                if let Some(language) = language
12696                                    && language.name() == "Markdown".into()
12697                                {
12698                                    edit_for_markdown_paste(
12699                                        &snapshot,
12700                                        range,
12701                                        to_insert,
12702                                        url::Url::parse(to_insert).ok(),
12703                                    )
12704                                } else {
12705                                    (range, Cow::Borrowed(to_insert))
12706                                }
12707                            };
12708
12709                        edits.push((range, to_insert));
12710                        original_indent_columns.push(original_indent_column);
12711                    }
12712                    drop(snapshot);
12713
12714                    buffer.edit(
12715                        edits,
12716                        if auto_indent_on_paste {
12717                            Some(AutoindentMode::Block {
12718                                original_indent_columns,
12719                            })
12720                        } else {
12721                            None
12722                        },
12723                        cx,
12724                    );
12725                });
12726
12727                let selections = this.selections.all::<usize>(cx);
12728                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12729            } else {
12730                let url = url::Url::parse(&clipboard_text).ok();
12731
12732                let auto_indent_mode = if !clipboard_text.is_empty() {
12733                    Some(AutoindentMode::Block {
12734                        original_indent_columns: Vec::new(),
12735                    })
12736                } else {
12737                    None
12738                };
12739
12740                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12741                    let snapshot = buffer.snapshot(cx);
12742
12743                    let anchors = old_selections
12744                        .iter()
12745                        .map(|s| {
12746                            let anchor = snapshot.anchor_after(s.head());
12747                            s.map(|_| anchor)
12748                        })
12749                        .collect::<Vec<_>>();
12750
12751                    let mut edits = Vec::new();
12752
12753                    for selection in old_selections.iter() {
12754                        let language = snapshot.language_at(selection.head());
12755                        let range = selection.range();
12756
12757                        let (edit_range, edit_text) = if let Some(language) = language
12758                            && language.name() == "Markdown".into()
12759                        {
12760                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12761                        } else {
12762                            (range, clipboard_text.clone())
12763                        };
12764
12765                        edits.push((edit_range, edit_text));
12766                    }
12767
12768                    drop(snapshot);
12769                    buffer.edit(edits, auto_indent_mode, cx);
12770
12771                    anchors
12772                });
12773
12774                this.change_selections(Default::default(), window, cx, |s| {
12775                    s.select_anchors(selection_anchors);
12776                });
12777            }
12778
12779            let trigger_in_words =
12780                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12781
12782            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12783        });
12784    }
12785
12786    pub fn diff_clipboard_with_selection(
12787        &mut self,
12788        _: &DiffClipboardWithSelection,
12789        window: &mut Window,
12790        cx: &mut Context<Self>,
12791    ) {
12792        let selections = self.selections.all::<usize>(cx);
12793
12794        if selections.is_empty() {
12795            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12796            return;
12797        };
12798
12799        let clipboard_text = match cx.read_from_clipboard() {
12800            Some(item) => match item.entries().first() {
12801                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12802                _ => None,
12803            },
12804            None => None,
12805        };
12806
12807        let Some(clipboard_text) = clipboard_text else {
12808            log::warn!("Clipboard doesn't contain text.");
12809            return;
12810        };
12811
12812        window.dispatch_action(
12813            Box::new(DiffClipboardWithSelectionData {
12814                clipboard_text,
12815                editor: cx.entity(),
12816            }),
12817            cx,
12818        );
12819    }
12820
12821    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12823        if let Some(item) = cx.read_from_clipboard() {
12824            let entries = item.entries();
12825
12826            match entries.first() {
12827                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12828                // of all the pasted entries.
12829                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12830                    .do_paste(
12831                        clipboard_string.text(),
12832                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12833                        true,
12834                        window,
12835                        cx,
12836                    ),
12837                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12838            }
12839        }
12840    }
12841
12842    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12843        if self.read_only(cx) {
12844            return;
12845        }
12846
12847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12848
12849        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12850            if let Some((selections, _)) =
12851                self.selection_history.transaction(transaction_id).cloned()
12852            {
12853                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12854                    s.select_anchors(selections.to_vec());
12855                });
12856            } else {
12857                log::error!(
12858                    "No entry in selection_history found for undo. \
12859                     This may correspond to a bug where undo does not update the selection. \
12860                     If this is occurring, please add details to \
12861                     https://github.com/zed-industries/zed/issues/22692"
12862                );
12863            }
12864            self.request_autoscroll(Autoscroll::fit(), cx);
12865            self.unmark_text(window, cx);
12866            self.refresh_edit_prediction(true, false, window, cx);
12867            cx.emit(EditorEvent::Edited { transaction_id });
12868            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12869        }
12870    }
12871
12872    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12873        if self.read_only(cx) {
12874            return;
12875        }
12876
12877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12878
12879        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12880            if let Some((_, Some(selections))) =
12881                self.selection_history.transaction(transaction_id).cloned()
12882            {
12883                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12884                    s.select_anchors(selections.to_vec());
12885                });
12886            } else {
12887                log::error!(
12888                    "No entry in selection_history found for redo. \
12889                     This may correspond to a bug where undo does not update the selection. \
12890                     If this is occurring, please add details to \
12891                     https://github.com/zed-industries/zed/issues/22692"
12892                );
12893            }
12894            self.request_autoscroll(Autoscroll::fit(), cx);
12895            self.unmark_text(window, cx);
12896            self.refresh_edit_prediction(true, false, window, cx);
12897            cx.emit(EditorEvent::Edited { transaction_id });
12898        }
12899    }
12900
12901    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12902        self.buffer
12903            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12904    }
12905
12906    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12907        self.buffer
12908            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12909    }
12910
12911    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_with(|map, selection| {
12915                let cursor = if selection.is_empty() {
12916                    movement::left(map, selection.start)
12917                } else {
12918                    selection.start
12919                };
12920                selection.collapse_to(cursor, SelectionGoal::None);
12921            });
12922        })
12923    }
12924
12925    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12929        })
12930    }
12931
12932    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12933        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12934        self.change_selections(Default::default(), window, cx, |s| {
12935            s.move_with(|map, selection| {
12936                let cursor = if selection.is_empty() {
12937                    movement::right(map, selection.end)
12938                } else {
12939                    selection.end
12940                };
12941                selection.collapse_to(cursor, SelectionGoal::None)
12942            });
12943        })
12944    }
12945
12946    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12948        self.change_selections(Default::default(), window, cx, |s| {
12949            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12950        });
12951    }
12952
12953    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12954        if self.take_rename(true, window, cx).is_some() {
12955            return;
12956        }
12957
12958        if self.mode.is_single_line() {
12959            cx.propagate();
12960            return;
12961        }
12962
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12964
12965        let text_layout_details = &self.text_layout_details(window);
12966        let selection_count = self.selections.count();
12967        let first_selection = self.selections.first_anchor();
12968
12969        self.change_selections(Default::default(), window, cx, |s| {
12970            s.move_with(|map, selection| {
12971                if !selection.is_empty() {
12972                    selection.goal = SelectionGoal::None;
12973                }
12974                let (cursor, goal) = movement::up(
12975                    map,
12976                    selection.start,
12977                    selection.goal,
12978                    false,
12979                    text_layout_details,
12980                );
12981                selection.collapse_to(cursor, goal);
12982            });
12983        });
12984
12985        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12986        {
12987            cx.propagate();
12988        }
12989    }
12990
12991    pub fn move_up_by_lines(
12992        &mut self,
12993        action: &MoveUpByLines,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) {
12997        if self.take_rename(true, window, cx).is_some() {
12998            return;
12999        }
13000
13001        if self.mode.is_single_line() {
13002            cx.propagate();
13003            return;
13004        }
13005
13006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13007
13008        let text_layout_details = &self.text_layout_details(window);
13009
13010        self.change_selections(Default::default(), window, cx, |s| {
13011            s.move_with(|map, selection| {
13012                if !selection.is_empty() {
13013                    selection.goal = SelectionGoal::None;
13014                }
13015                let (cursor, goal) = movement::up_by_rows(
13016                    map,
13017                    selection.start,
13018                    action.lines,
13019                    selection.goal,
13020                    false,
13021                    text_layout_details,
13022                );
13023                selection.collapse_to(cursor, goal);
13024            });
13025        })
13026    }
13027
13028    pub fn move_down_by_lines(
13029        &mut self,
13030        action: &MoveDownByLines,
13031        window: &mut Window,
13032        cx: &mut Context<Self>,
13033    ) {
13034        if self.take_rename(true, window, cx).is_some() {
13035            return;
13036        }
13037
13038        if self.mode.is_single_line() {
13039            cx.propagate();
13040            return;
13041        }
13042
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044
13045        let text_layout_details = &self.text_layout_details(window);
13046
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_with(|map, selection| {
13049                if !selection.is_empty() {
13050                    selection.goal = SelectionGoal::None;
13051                }
13052                let (cursor, goal) = movement::down_by_rows(
13053                    map,
13054                    selection.start,
13055                    action.lines,
13056                    selection.goal,
13057                    false,
13058                    text_layout_details,
13059                );
13060                selection.collapse_to(cursor, goal);
13061            });
13062        })
13063    }
13064
13065    pub fn select_down_by_lines(
13066        &mut self,
13067        action: &SelectDownByLines,
13068        window: &mut Window,
13069        cx: &mut Context<Self>,
13070    ) {
13071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13072        let text_layout_details = &self.text_layout_details(window);
13073        self.change_selections(Default::default(), window, cx, |s| {
13074            s.move_heads_with(|map, head, goal| {
13075                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13076            })
13077        })
13078    }
13079
13080    pub fn select_up_by_lines(
13081        &mut self,
13082        action: &SelectUpByLines,
13083        window: &mut Window,
13084        cx: &mut Context<Self>,
13085    ) {
13086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13087        let text_layout_details = &self.text_layout_details(window);
13088        self.change_selections(Default::default(), window, cx, |s| {
13089            s.move_heads_with(|map, head, goal| {
13090                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13091            })
13092        })
13093    }
13094
13095    pub fn select_page_up(
13096        &mut self,
13097        _: &SelectPageUp,
13098        window: &mut Window,
13099        cx: &mut Context<Self>,
13100    ) {
13101        let Some(row_count) = self.visible_row_count() else {
13102            return;
13103        };
13104
13105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13106
13107        let text_layout_details = &self.text_layout_details(window);
13108
13109        self.change_selections(Default::default(), window, cx, |s| {
13110            s.move_heads_with(|map, head, goal| {
13111                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13112            })
13113        })
13114    }
13115
13116    pub fn move_page_up(
13117        &mut self,
13118        action: &MovePageUp,
13119        window: &mut Window,
13120        cx: &mut Context<Self>,
13121    ) {
13122        if self.take_rename(true, window, cx).is_some() {
13123            return;
13124        }
13125
13126        if self
13127            .context_menu
13128            .borrow_mut()
13129            .as_mut()
13130            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13131            .unwrap_or(false)
13132        {
13133            return;
13134        }
13135
13136        if matches!(self.mode, EditorMode::SingleLine) {
13137            cx.propagate();
13138            return;
13139        }
13140
13141        let Some(row_count) = self.visible_row_count() else {
13142            return;
13143        };
13144
13145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13146
13147        let effects = if action.center_cursor {
13148            SelectionEffects::scroll(Autoscroll::center())
13149        } else {
13150            SelectionEffects::default()
13151        };
13152
13153        let text_layout_details = &self.text_layout_details(window);
13154
13155        self.change_selections(effects, window, cx, |s| {
13156            s.move_with(|map, selection| {
13157                if !selection.is_empty() {
13158                    selection.goal = SelectionGoal::None;
13159                }
13160                let (cursor, goal) = movement::up_by_rows(
13161                    map,
13162                    selection.end,
13163                    row_count,
13164                    selection.goal,
13165                    false,
13166                    text_layout_details,
13167                );
13168                selection.collapse_to(cursor, goal);
13169            });
13170        });
13171    }
13172
13173    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13174        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13175        let text_layout_details = &self.text_layout_details(window);
13176        self.change_selections(Default::default(), window, cx, |s| {
13177            s.move_heads_with(|map, head, goal| {
13178                movement::up(map, head, goal, false, text_layout_details)
13179            })
13180        })
13181    }
13182
13183    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13184        self.take_rename(true, window, cx);
13185
13186        if self.mode.is_single_line() {
13187            cx.propagate();
13188            return;
13189        }
13190
13191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13192
13193        let text_layout_details = &self.text_layout_details(window);
13194        let selection_count = self.selections.count();
13195        let first_selection = self.selections.first_anchor();
13196
13197        self.change_selections(Default::default(), window, cx, |s| {
13198            s.move_with(|map, selection| {
13199                if !selection.is_empty() {
13200                    selection.goal = SelectionGoal::None;
13201                }
13202                let (cursor, goal) = movement::down(
13203                    map,
13204                    selection.end,
13205                    selection.goal,
13206                    false,
13207                    text_layout_details,
13208                );
13209                selection.collapse_to(cursor, goal);
13210            });
13211        });
13212
13213        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13214        {
13215            cx.propagate();
13216        }
13217    }
13218
13219    pub fn select_page_down(
13220        &mut self,
13221        _: &SelectPageDown,
13222        window: &mut Window,
13223        cx: &mut Context<Self>,
13224    ) {
13225        let Some(row_count) = self.visible_row_count() else {
13226            return;
13227        };
13228
13229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13230
13231        let text_layout_details = &self.text_layout_details(window);
13232
13233        self.change_selections(Default::default(), window, cx, |s| {
13234            s.move_heads_with(|map, head, goal| {
13235                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13236            })
13237        })
13238    }
13239
13240    pub fn move_page_down(
13241        &mut self,
13242        action: &MovePageDown,
13243        window: &mut Window,
13244        cx: &mut Context<Self>,
13245    ) {
13246        if self.take_rename(true, window, cx).is_some() {
13247            return;
13248        }
13249
13250        if self
13251            .context_menu
13252            .borrow_mut()
13253            .as_mut()
13254            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13255            .unwrap_or(false)
13256        {
13257            return;
13258        }
13259
13260        if matches!(self.mode, EditorMode::SingleLine) {
13261            cx.propagate();
13262            return;
13263        }
13264
13265        let Some(row_count) = self.visible_row_count() else {
13266            return;
13267        };
13268
13269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13270
13271        let effects = if action.center_cursor {
13272            SelectionEffects::scroll(Autoscroll::center())
13273        } else {
13274            SelectionEffects::default()
13275        };
13276
13277        let text_layout_details = &self.text_layout_details(window);
13278        self.change_selections(effects, window, cx, |s| {
13279            s.move_with(|map, selection| {
13280                if !selection.is_empty() {
13281                    selection.goal = SelectionGoal::None;
13282                }
13283                let (cursor, goal) = movement::down_by_rows(
13284                    map,
13285                    selection.end,
13286                    row_count,
13287                    selection.goal,
13288                    false,
13289                    text_layout_details,
13290                );
13291                selection.collapse_to(cursor, goal);
13292            });
13293        });
13294    }
13295
13296    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13298        let text_layout_details = &self.text_layout_details(window);
13299        self.change_selections(Default::default(), window, cx, |s| {
13300            s.move_heads_with(|map, head, goal| {
13301                movement::down(map, head, goal, false, text_layout_details)
13302            })
13303        });
13304    }
13305
13306    pub fn context_menu_first(
13307        &mut self,
13308        _: &ContextMenuFirst,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13313            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13314        }
13315    }
13316
13317    pub fn context_menu_prev(
13318        &mut self,
13319        _: &ContextMenuPrevious,
13320        window: &mut Window,
13321        cx: &mut Context<Self>,
13322    ) {
13323        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13324            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13325        }
13326    }
13327
13328    pub fn context_menu_next(
13329        &mut self,
13330        _: &ContextMenuNext,
13331        window: &mut Window,
13332        cx: &mut Context<Self>,
13333    ) {
13334        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13335            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13336        }
13337    }
13338
13339    pub fn context_menu_last(
13340        &mut self,
13341        _: &ContextMenuLast,
13342        window: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) {
13345        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13346            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13347        }
13348    }
13349
13350    pub fn signature_help_prev(
13351        &mut self,
13352        _: &SignatureHelpPrevious,
13353        _: &mut Window,
13354        cx: &mut Context<Self>,
13355    ) {
13356        if let Some(popover) = self.signature_help_state.popover_mut() {
13357            if popover.current_signature == 0 {
13358                popover.current_signature = popover.signatures.len() - 1;
13359            } else {
13360                popover.current_signature -= 1;
13361            }
13362            cx.notify();
13363        }
13364    }
13365
13366    pub fn signature_help_next(
13367        &mut self,
13368        _: &SignatureHelpNext,
13369        _: &mut Window,
13370        cx: &mut Context<Self>,
13371    ) {
13372        if let Some(popover) = self.signature_help_state.popover_mut() {
13373            if popover.current_signature + 1 == popover.signatures.len() {
13374                popover.current_signature = 0;
13375            } else {
13376                popover.current_signature += 1;
13377            }
13378            cx.notify();
13379        }
13380    }
13381
13382    pub fn move_to_previous_word_start(
13383        &mut self,
13384        _: &MoveToPreviousWordStart,
13385        window: &mut Window,
13386        cx: &mut Context<Self>,
13387    ) {
13388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13389        self.change_selections(Default::default(), window, cx, |s| {
13390            s.move_cursors_with(|map, head, _| {
13391                (
13392                    movement::previous_word_start(map, head),
13393                    SelectionGoal::None,
13394                )
13395            });
13396        })
13397    }
13398
13399    pub fn move_to_previous_subword_start(
13400        &mut self,
13401        _: &MoveToPreviousSubwordStart,
13402        window: &mut Window,
13403        cx: &mut Context<Self>,
13404    ) {
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13406        self.change_selections(Default::default(), window, cx, |s| {
13407            s.move_cursors_with(|map, head, _| {
13408                (
13409                    movement::previous_subword_start(map, head),
13410                    SelectionGoal::None,
13411                )
13412            });
13413        })
13414    }
13415
13416    pub fn select_to_previous_word_start(
13417        &mut self,
13418        _: &SelectToPreviousWordStart,
13419        window: &mut Window,
13420        cx: &mut Context<Self>,
13421    ) {
13422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13423        self.change_selections(Default::default(), window, cx, |s| {
13424            s.move_heads_with(|map, head, _| {
13425                (
13426                    movement::previous_word_start(map, head),
13427                    SelectionGoal::None,
13428                )
13429            });
13430        })
13431    }
13432
13433    pub fn select_to_previous_subword_start(
13434        &mut self,
13435        _: &SelectToPreviousSubwordStart,
13436        window: &mut Window,
13437        cx: &mut Context<Self>,
13438    ) {
13439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13440        self.change_selections(Default::default(), window, cx, |s| {
13441            s.move_heads_with(|map, head, _| {
13442                (
13443                    movement::previous_subword_start(map, head),
13444                    SelectionGoal::None,
13445                )
13446            });
13447        })
13448    }
13449
13450    pub fn delete_to_previous_word_start(
13451        &mut self,
13452        action: &DeleteToPreviousWordStart,
13453        window: &mut Window,
13454        cx: &mut Context<Self>,
13455    ) {
13456        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13457        self.transact(window, cx, |this, window, cx| {
13458            this.select_autoclose_pair(window, cx);
13459            this.change_selections(Default::default(), window, cx, |s| {
13460                s.move_with(|map, selection| {
13461                    if selection.is_empty() {
13462                        let mut cursor = if action.ignore_newlines {
13463                            movement::previous_word_start(map, selection.head())
13464                        } else {
13465                            movement::previous_word_start_or_newline(map, selection.head())
13466                        };
13467                        cursor = movement::adjust_greedy_deletion(
13468                            map,
13469                            selection.head(),
13470                            cursor,
13471                            action.ignore_brackets,
13472                        );
13473                        selection.set_head(cursor, SelectionGoal::None);
13474                    }
13475                });
13476            });
13477            this.insert("", window, cx);
13478        });
13479    }
13480
13481    pub fn delete_to_previous_subword_start(
13482        &mut self,
13483        _: &DeleteToPreviousSubwordStart,
13484        window: &mut Window,
13485        cx: &mut Context<Self>,
13486    ) {
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13488        self.transact(window, cx, |this, window, cx| {
13489            this.select_autoclose_pair(window, cx);
13490            this.change_selections(Default::default(), window, cx, |s| {
13491                s.move_with(|map, selection| {
13492                    if selection.is_empty() {
13493                        let mut cursor = movement::previous_subword_start(map, selection.head());
13494                        cursor =
13495                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13496                        selection.set_head(cursor, SelectionGoal::None);
13497                    }
13498                });
13499            });
13500            this.insert("", window, cx);
13501        });
13502    }
13503
13504    pub fn move_to_next_word_end(
13505        &mut self,
13506        _: &MoveToNextWordEnd,
13507        window: &mut Window,
13508        cx: &mut Context<Self>,
13509    ) {
13510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13511        self.change_selections(Default::default(), window, cx, |s| {
13512            s.move_cursors_with(|map, head, _| {
13513                (movement::next_word_end(map, head), SelectionGoal::None)
13514            });
13515        })
13516    }
13517
13518    pub fn move_to_next_subword_end(
13519        &mut self,
13520        _: &MoveToNextSubwordEnd,
13521        window: &mut Window,
13522        cx: &mut Context<Self>,
13523    ) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525        self.change_selections(Default::default(), window, cx, |s| {
13526            s.move_cursors_with(|map, head, _| {
13527                (movement::next_subword_end(map, head), SelectionGoal::None)
13528            });
13529        })
13530    }
13531
13532    pub fn select_to_next_word_end(
13533        &mut self,
13534        _: &SelectToNextWordEnd,
13535        window: &mut Window,
13536        cx: &mut Context<Self>,
13537    ) {
13538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13539        self.change_selections(Default::default(), window, cx, |s| {
13540            s.move_heads_with(|map, head, _| {
13541                (movement::next_word_end(map, head), SelectionGoal::None)
13542            });
13543        })
13544    }
13545
13546    pub fn select_to_next_subword_end(
13547        &mut self,
13548        _: &SelectToNextSubwordEnd,
13549        window: &mut Window,
13550        cx: &mut Context<Self>,
13551    ) {
13552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13553        self.change_selections(Default::default(), window, cx, |s| {
13554            s.move_heads_with(|map, head, _| {
13555                (movement::next_subword_end(map, head), SelectionGoal::None)
13556            });
13557        })
13558    }
13559
13560    pub fn delete_to_next_word_end(
13561        &mut self,
13562        action: &DeleteToNextWordEnd,
13563        window: &mut Window,
13564        cx: &mut Context<Self>,
13565    ) {
13566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13567        self.transact(window, cx, |this, window, cx| {
13568            this.change_selections(Default::default(), window, cx, |s| {
13569                s.move_with(|map, selection| {
13570                    if selection.is_empty() {
13571                        let mut cursor = if action.ignore_newlines {
13572                            movement::next_word_end(map, selection.head())
13573                        } else {
13574                            movement::next_word_end_or_newline(map, selection.head())
13575                        };
13576                        cursor = movement::adjust_greedy_deletion(
13577                            map,
13578                            selection.head(),
13579                            cursor,
13580                            action.ignore_brackets,
13581                        );
13582                        selection.set_head(cursor, SelectionGoal::None);
13583                    }
13584                });
13585            });
13586            this.insert("", window, cx);
13587        });
13588    }
13589
13590    pub fn delete_to_next_subword_end(
13591        &mut self,
13592        _: &DeleteToNextSubwordEnd,
13593        window: &mut Window,
13594        cx: &mut Context<Self>,
13595    ) {
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13597        self.transact(window, cx, |this, window, cx| {
13598            this.change_selections(Default::default(), window, cx, |s| {
13599                s.move_with(|map, selection| {
13600                    if selection.is_empty() {
13601                        let mut cursor = movement::next_subword_end(map, selection.head());
13602                        cursor =
13603                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13604                        selection.set_head(cursor, SelectionGoal::None);
13605                    }
13606                });
13607            });
13608            this.insert("", window, cx);
13609        });
13610    }
13611
13612    pub fn move_to_beginning_of_line(
13613        &mut self,
13614        action: &MoveToBeginningOfLine,
13615        window: &mut Window,
13616        cx: &mut Context<Self>,
13617    ) {
13618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13619        self.change_selections(Default::default(), window, cx, |s| {
13620            s.move_cursors_with(|map, head, _| {
13621                (
13622                    movement::indented_line_beginning(
13623                        map,
13624                        head,
13625                        action.stop_at_soft_wraps,
13626                        action.stop_at_indent,
13627                    ),
13628                    SelectionGoal::None,
13629                )
13630            });
13631        })
13632    }
13633
13634    pub fn select_to_beginning_of_line(
13635        &mut self,
13636        action: &SelectToBeginningOfLine,
13637        window: &mut Window,
13638        cx: &mut Context<Self>,
13639    ) {
13640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13641        self.change_selections(Default::default(), window, cx, |s| {
13642            s.move_heads_with(|map, head, _| {
13643                (
13644                    movement::indented_line_beginning(
13645                        map,
13646                        head,
13647                        action.stop_at_soft_wraps,
13648                        action.stop_at_indent,
13649                    ),
13650                    SelectionGoal::None,
13651                )
13652            });
13653        });
13654    }
13655
13656    pub fn delete_to_beginning_of_line(
13657        &mut self,
13658        action: &DeleteToBeginningOfLine,
13659        window: &mut Window,
13660        cx: &mut Context<Self>,
13661    ) {
13662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13663        self.transact(window, cx, |this, window, cx| {
13664            this.change_selections(Default::default(), window, cx, |s| {
13665                s.move_with(|_, selection| {
13666                    selection.reversed = true;
13667                });
13668            });
13669
13670            this.select_to_beginning_of_line(
13671                &SelectToBeginningOfLine {
13672                    stop_at_soft_wraps: false,
13673                    stop_at_indent: action.stop_at_indent,
13674                },
13675                window,
13676                cx,
13677            );
13678            this.backspace(&Backspace, window, cx);
13679        });
13680    }
13681
13682    pub fn move_to_end_of_line(
13683        &mut self,
13684        action: &MoveToEndOfLine,
13685        window: &mut Window,
13686        cx: &mut Context<Self>,
13687    ) {
13688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13689        self.change_selections(Default::default(), window, cx, |s| {
13690            s.move_cursors_with(|map, head, _| {
13691                (
13692                    movement::line_end(map, head, action.stop_at_soft_wraps),
13693                    SelectionGoal::None,
13694                )
13695            });
13696        })
13697    }
13698
13699    pub fn select_to_end_of_line(
13700        &mut self,
13701        action: &SelectToEndOfLine,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13706        self.change_selections(Default::default(), window, cx, |s| {
13707            s.move_heads_with(|map, head, _| {
13708                (
13709                    movement::line_end(map, head, action.stop_at_soft_wraps),
13710                    SelectionGoal::None,
13711                )
13712            });
13713        })
13714    }
13715
13716    pub fn delete_to_end_of_line(
13717        &mut self,
13718        _: &DeleteToEndOfLine,
13719        window: &mut Window,
13720        cx: &mut Context<Self>,
13721    ) {
13722        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13723        self.transact(window, cx, |this, window, cx| {
13724            this.select_to_end_of_line(
13725                &SelectToEndOfLine {
13726                    stop_at_soft_wraps: false,
13727                },
13728                window,
13729                cx,
13730            );
13731            this.delete(&Delete, window, cx);
13732        });
13733    }
13734
13735    pub fn cut_to_end_of_line(
13736        &mut self,
13737        action: &CutToEndOfLine,
13738        window: &mut Window,
13739        cx: &mut Context<Self>,
13740    ) {
13741        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13742        self.transact(window, cx, |this, window, cx| {
13743            this.select_to_end_of_line(
13744                &SelectToEndOfLine {
13745                    stop_at_soft_wraps: false,
13746                },
13747                window,
13748                cx,
13749            );
13750            if !action.stop_at_newlines {
13751                this.change_selections(Default::default(), window, cx, |s| {
13752                    s.move_with(|_, sel| {
13753                        if sel.is_empty() {
13754                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13755                        }
13756                    });
13757                });
13758            }
13759            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13760            let item = this.cut_common(false, window, cx);
13761            cx.write_to_clipboard(item);
13762        });
13763    }
13764
13765    pub fn move_to_start_of_paragraph(
13766        &mut self,
13767        _: &MoveToStartOfParagraph,
13768        window: &mut Window,
13769        cx: &mut Context<Self>,
13770    ) {
13771        if matches!(self.mode, EditorMode::SingleLine) {
13772            cx.propagate();
13773            return;
13774        }
13775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13776        self.change_selections(Default::default(), window, cx, |s| {
13777            s.move_with(|map, selection| {
13778                selection.collapse_to(
13779                    movement::start_of_paragraph(map, selection.head(), 1),
13780                    SelectionGoal::None,
13781                )
13782            });
13783        })
13784    }
13785
13786    pub fn move_to_end_of_paragraph(
13787        &mut self,
13788        _: &MoveToEndOfParagraph,
13789        window: &mut Window,
13790        cx: &mut Context<Self>,
13791    ) {
13792        if matches!(self.mode, EditorMode::SingleLine) {
13793            cx.propagate();
13794            return;
13795        }
13796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13797        self.change_selections(Default::default(), window, cx, |s| {
13798            s.move_with(|map, selection| {
13799                selection.collapse_to(
13800                    movement::end_of_paragraph(map, selection.head(), 1),
13801                    SelectionGoal::None,
13802                )
13803            });
13804        })
13805    }
13806
13807    pub fn select_to_start_of_paragraph(
13808        &mut self,
13809        _: &SelectToStartOfParagraph,
13810        window: &mut Window,
13811        cx: &mut Context<Self>,
13812    ) {
13813        if matches!(self.mode, EditorMode::SingleLine) {
13814            cx.propagate();
13815            return;
13816        }
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13818        self.change_selections(Default::default(), window, cx, |s| {
13819            s.move_heads_with(|map, head, _| {
13820                (
13821                    movement::start_of_paragraph(map, head, 1),
13822                    SelectionGoal::None,
13823                )
13824            });
13825        })
13826    }
13827
13828    pub fn select_to_end_of_paragraph(
13829        &mut self,
13830        _: &SelectToEndOfParagraph,
13831        window: &mut Window,
13832        cx: &mut Context<Self>,
13833    ) {
13834        if matches!(self.mode, EditorMode::SingleLine) {
13835            cx.propagate();
13836            return;
13837        }
13838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13839        self.change_selections(Default::default(), window, cx, |s| {
13840            s.move_heads_with(|map, head, _| {
13841                (
13842                    movement::end_of_paragraph(map, head, 1),
13843                    SelectionGoal::None,
13844                )
13845            });
13846        })
13847    }
13848
13849    pub fn move_to_start_of_excerpt(
13850        &mut self,
13851        _: &MoveToStartOfExcerpt,
13852        window: &mut Window,
13853        cx: &mut Context<Self>,
13854    ) {
13855        if matches!(self.mode, EditorMode::SingleLine) {
13856            cx.propagate();
13857            return;
13858        }
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13860        self.change_selections(Default::default(), window, cx, |s| {
13861            s.move_with(|map, selection| {
13862                selection.collapse_to(
13863                    movement::start_of_excerpt(
13864                        map,
13865                        selection.head(),
13866                        workspace::searchable::Direction::Prev,
13867                    ),
13868                    SelectionGoal::None,
13869                )
13870            });
13871        })
13872    }
13873
13874    pub fn move_to_start_of_next_excerpt(
13875        &mut self,
13876        _: &MoveToStartOfNextExcerpt,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        if matches!(self.mode, EditorMode::SingleLine) {
13881            cx.propagate();
13882            return;
13883        }
13884
13885        self.change_selections(Default::default(), window, cx, |s| {
13886            s.move_with(|map, selection| {
13887                selection.collapse_to(
13888                    movement::start_of_excerpt(
13889                        map,
13890                        selection.head(),
13891                        workspace::searchable::Direction::Next,
13892                    ),
13893                    SelectionGoal::None,
13894                )
13895            });
13896        })
13897    }
13898
13899    pub fn move_to_end_of_excerpt(
13900        &mut self,
13901        _: &MoveToEndOfExcerpt,
13902        window: &mut Window,
13903        cx: &mut Context<Self>,
13904    ) {
13905        if matches!(self.mode, EditorMode::SingleLine) {
13906            cx.propagate();
13907            return;
13908        }
13909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13910        self.change_selections(Default::default(), window, cx, |s| {
13911            s.move_with(|map, selection| {
13912                selection.collapse_to(
13913                    movement::end_of_excerpt(
13914                        map,
13915                        selection.head(),
13916                        workspace::searchable::Direction::Next,
13917                    ),
13918                    SelectionGoal::None,
13919                )
13920            });
13921        })
13922    }
13923
13924    pub fn move_to_end_of_previous_excerpt(
13925        &mut self,
13926        _: &MoveToEndOfPreviousExcerpt,
13927        window: &mut Window,
13928        cx: &mut Context<Self>,
13929    ) {
13930        if matches!(self.mode, EditorMode::SingleLine) {
13931            cx.propagate();
13932            return;
13933        }
13934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13935        self.change_selections(Default::default(), window, cx, |s| {
13936            s.move_with(|map, selection| {
13937                selection.collapse_to(
13938                    movement::end_of_excerpt(
13939                        map,
13940                        selection.head(),
13941                        workspace::searchable::Direction::Prev,
13942                    ),
13943                    SelectionGoal::None,
13944                )
13945            });
13946        })
13947    }
13948
13949    pub fn select_to_start_of_excerpt(
13950        &mut self,
13951        _: &SelectToStartOfExcerpt,
13952        window: &mut Window,
13953        cx: &mut Context<Self>,
13954    ) {
13955        if matches!(self.mode, EditorMode::SingleLine) {
13956            cx.propagate();
13957            return;
13958        }
13959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13960        self.change_selections(Default::default(), window, cx, |s| {
13961            s.move_heads_with(|map, head, _| {
13962                (
13963                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13964                    SelectionGoal::None,
13965                )
13966            });
13967        })
13968    }
13969
13970    pub fn select_to_start_of_next_excerpt(
13971        &mut self,
13972        _: &SelectToStartOfNextExcerpt,
13973        window: &mut Window,
13974        cx: &mut Context<Self>,
13975    ) {
13976        if matches!(self.mode, EditorMode::SingleLine) {
13977            cx.propagate();
13978            return;
13979        }
13980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13981        self.change_selections(Default::default(), window, cx, |s| {
13982            s.move_heads_with(|map, head, _| {
13983                (
13984                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13985                    SelectionGoal::None,
13986                )
13987            });
13988        })
13989    }
13990
13991    pub fn select_to_end_of_excerpt(
13992        &mut self,
13993        _: &SelectToEndOfExcerpt,
13994        window: &mut Window,
13995        cx: &mut Context<Self>,
13996    ) {
13997        if matches!(self.mode, EditorMode::SingleLine) {
13998            cx.propagate();
13999            return;
14000        }
14001        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14002        self.change_selections(Default::default(), window, cx, |s| {
14003            s.move_heads_with(|map, head, _| {
14004                (
14005                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14006                    SelectionGoal::None,
14007                )
14008            });
14009        })
14010    }
14011
14012    pub fn select_to_end_of_previous_excerpt(
14013        &mut self,
14014        _: &SelectToEndOfPreviousExcerpt,
14015        window: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) {
14018        if matches!(self.mode, EditorMode::SingleLine) {
14019            cx.propagate();
14020            return;
14021        }
14022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14023        self.change_selections(Default::default(), window, cx, |s| {
14024            s.move_heads_with(|map, head, _| {
14025                (
14026                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14027                    SelectionGoal::None,
14028                )
14029            });
14030        })
14031    }
14032
14033    pub fn move_to_beginning(
14034        &mut self,
14035        _: &MoveToBeginning,
14036        window: &mut Window,
14037        cx: &mut Context<Self>,
14038    ) {
14039        if matches!(self.mode, EditorMode::SingleLine) {
14040            cx.propagate();
14041            return;
14042        }
14043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14044        self.change_selections(Default::default(), window, cx, |s| {
14045            s.select_ranges(vec![0..0]);
14046        });
14047    }
14048
14049    pub fn select_to_beginning(
14050        &mut self,
14051        _: &SelectToBeginning,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        let mut selection = self.selections.last::<Point>(cx);
14056        selection.set_head(Point::zero(), SelectionGoal::None);
14057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14058        self.change_selections(Default::default(), window, cx, |s| {
14059            s.select(vec![selection]);
14060        });
14061    }
14062
14063    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14064        if matches!(self.mode, EditorMode::SingleLine) {
14065            cx.propagate();
14066            return;
14067        }
14068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14069        let cursor = self.buffer.read(cx).read(cx).len();
14070        self.change_selections(Default::default(), window, cx, |s| {
14071            s.select_ranges(vec![cursor..cursor])
14072        });
14073    }
14074
14075    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14076        self.nav_history = nav_history;
14077    }
14078
14079    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14080        self.nav_history.as_ref()
14081    }
14082
14083    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14084        self.push_to_nav_history(
14085            self.selections.newest_anchor().head(),
14086            None,
14087            false,
14088            true,
14089            cx,
14090        );
14091    }
14092
14093    fn push_to_nav_history(
14094        &mut self,
14095        cursor_anchor: Anchor,
14096        new_position: Option<Point>,
14097        is_deactivate: bool,
14098        always: bool,
14099        cx: &mut Context<Self>,
14100    ) {
14101        if let Some(nav_history) = self.nav_history.as_mut() {
14102            let buffer = self.buffer.read(cx).read(cx);
14103            let cursor_position = cursor_anchor.to_point(&buffer);
14104            let scroll_state = self.scroll_manager.anchor();
14105            let scroll_top_row = scroll_state.top_row(&buffer);
14106            drop(buffer);
14107
14108            if let Some(new_position) = new_position {
14109                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14110                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14111                    return;
14112                }
14113            }
14114
14115            nav_history.push(
14116                Some(NavigationData {
14117                    cursor_anchor,
14118                    cursor_position,
14119                    scroll_anchor: scroll_state,
14120                    scroll_top_row,
14121                }),
14122                cx,
14123            );
14124            cx.emit(EditorEvent::PushedToNavHistory {
14125                anchor: cursor_anchor,
14126                is_deactivate,
14127            })
14128        }
14129    }
14130
14131    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14133        let buffer = self.buffer.read(cx).snapshot(cx);
14134        let mut selection = self.selections.first::<usize>(cx);
14135        selection.set_head(buffer.len(), SelectionGoal::None);
14136        self.change_selections(Default::default(), window, cx, |s| {
14137            s.select(vec![selection]);
14138        });
14139    }
14140
14141    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14143        let end = self.buffer.read(cx).read(cx).len();
14144        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14145            s.select_ranges(vec![0..end]);
14146        });
14147    }
14148
14149    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14150        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14151        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14152        let mut selections = self.selections.all::<Point>(cx);
14153        let max_point = display_map.buffer_snapshot().max_point();
14154        for selection in &mut selections {
14155            let rows = selection.spanned_rows(true, &display_map);
14156            selection.start = Point::new(rows.start.0, 0);
14157            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14158            selection.reversed = false;
14159        }
14160        self.change_selections(Default::default(), window, cx, |s| {
14161            s.select(selections);
14162        });
14163    }
14164
14165    pub fn split_selection_into_lines(
14166        &mut self,
14167        action: &SplitSelectionIntoLines,
14168        window: &mut Window,
14169        cx: &mut Context<Self>,
14170    ) {
14171        let selections = self
14172            .selections
14173            .all::<Point>(cx)
14174            .into_iter()
14175            .map(|selection| selection.start..selection.end)
14176            .collect::<Vec<_>>();
14177        self.unfold_ranges(&selections, true, true, cx);
14178
14179        let mut new_selection_ranges = Vec::new();
14180        {
14181            let buffer = self.buffer.read(cx).read(cx);
14182            for selection in selections {
14183                for row in selection.start.row..selection.end.row {
14184                    let line_start = Point::new(row, 0);
14185                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14186
14187                    if action.keep_selections {
14188                        // Keep the selection range for each line
14189                        let selection_start = if row == selection.start.row {
14190                            selection.start
14191                        } else {
14192                            line_start
14193                        };
14194                        new_selection_ranges.push(selection_start..line_end);
14195                    } else {
14196                        // Collapse to cursor at end of line
14197                        new_selection_ranges.push(line_end..line_end);
14198                    }
14199                }
14200
14201                let is_multiline_selection = selection.start.row != selection.end.row;
14202                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14203                // so this action feels more ergonomic when paired with other selection operations
14204                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14205                if !should_skip_last {
14206                    if action.keep_selections {
14207                        if is_multiline_selection {
14208                            let line_start = Point::new(selection.end.row, 0);
14209                            new_selection_ranges.push(line_start..selection.end);
14210                        } else {
14211                            new_selection_ranges.push(selection.start..selection.end);
14212                        }
14213                    } else {
14214                        new_selection_ranges.push(selection.end..selection.end);
14215                    }
14216                }
14217            }
14218        }
14219        self.change_selections(Default::default(), window, cx, |s| {
14220            s.select_ranges(new_selection_ranges);
14221        });
14222    }
14223
14224    pub fn add_selection_above(
14225        &mut self,
14226        action: &AddSelectionAbove,
14227        window: &mut Window,
14228        cx: &mut Context<Self>,
14229    ) {
14230        self.add_selection(true, action.skip_soft_wrap, window, cx);
14231    }
14232
14233    pub fn add_selection_below(
14234        &mut self,
14235        action: &AddSelectionBelow,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) {
14239        self.add_selection(false, action.skip_soft_wrap, window, cx);
14240    }
14241
14242    fn add_selection(
14243        &mut self,
14244        above: bool,
14245        skip_soft_wrap: bool,
14246        window: &mut Window,
14247        cx: &mut Context<Self>,
14248    ) {
14249        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14250
14251        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14252        let all_selections = self.selections.all::<Point>(cx);
14253        let text_layout_details = self.text_layout_details(window);
14254
14255        let (mut columnar_selections, new_selections_to_columnarize) = {
14256            if let Some(state) = self.add_selections_state.as_ref() {
14257                let columnar_selection_ids: HashSet<_> = state
14258                    .groups
14259                    .iter()
14260                    .flat_map(|group| group.stack.iter())
14261                    .copied()
14262                    .collect();
14263
14264                all_selections
14265                    .into_iter()
14266                    .partition(|s| columnar_selection_ids.contains(&s.id))
14267            } else {
14268                (Vec::new(), all_selections)
14269            }
14270        };
14271
14272        let mut state = self
14273            .add_selections_state
14274            .take()
14275            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14276
14277        for selection in new_selections_to_columnarize {
14278            let range = selection.display_range(&display_map).sorted();
14279            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14280            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14281            let positions = start_x.min(end_x)..start_x.max(end_x);
14282            let mut stack = Vec::new();
14283            for row in range.start.row().0..=range.end.row().0 {
14284                if let Some(selection) = self.selections.build_columnar_selection(
14285                    &display_map,
14286                    DisplayRow(row),
14287                    &positions,
14288                    selection.reversed,
14289                    &text_layout_details,
14290                ) {
14291                    stack.push(selection.id);
14292                    columnar_selections.push(selection);
14293                }
14294            }
14295            if !stack.is_empty() {
14296                if above {
14297                    stack.reverse();
14298                }
14299                state.groups.push(AddSelectionsGroup { above, stack });
14300            }
14301        }
14302
14303        let mut final_selections = Vec::new();
14304        let end_row = if above {
14305            DisplayRow(0)
14306        } else {
14307            display_map.max_point().row()
14308        };
14309
14310        let mut last_added_item_per_group = HashMap::default();
14311        for group in state.groups.iter_mut() {
14312            if let Some(last_id) = group.stack.last() {
14313                last_added_item_per_group.insert(*last_id, group);
14314            }
14315        }
14316
14317        for selection in columnar_selections {
14318            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14319                if above == group.above {
14320                    let range = selection.display_range(&display_map).sorted();
14321                    debug_assert_eq!(range.start.row(), range.end.row());
14322                    let mut row = range.start.row();
14323                    let positions =
14324                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14325                            Pixels::from(start)..Pixels::from(end)
14326                        } else {
14327                            let start_x =
14328                                display_map.x_for_display_point(range.start, &text_layout_details);
14329                            let end_x =
14330                                display_map.x_for_display_point(range.end, &text_layout_details);
14331                            start_x.min(end_x)..start_x.max(end_x)
14332                        };
14333
14334                    let mut maybe_new_selection = None;
14335                    let direction = if above { -1 } else { 1 };
14336
14337                    while row != end_row {
14338                        if skip_soft_wrap {
14339                            row = display_map
14340                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14341                                .row();
14342                        } else if above {
14343                            row.0 -= 1;
14344                        } else {
14345                            row.0 += 1;
14346                        }
14347
14348                        if let Some(new_selection) = self.selections.build_columnar_selection(
14349                            &display_map,
14350                            row,
14351                            &positions,
14352                            selection.reversed,
14353                            &text_layout_details,
14354                        ) {
14355                            maybe_new_selection = Some(new_selection);
14356                            break;
14357                        }
14358                    }
14359
14360                    if let Some(new_selection) = maybe_new_selection {
14361                        group.stack.push(new_selection.id);
14362                        if above {
14363                            final_selections.push(new_selection);
14364                            final_selections.push(selection);
14365                        } else {
14366                            final_selections.push(selection);
14367                            final_selections.push(new_selection);
14368                        }
14369                    } else {
14370                        final_selections.push(selection);
14371                    }
14372                } else {
14373                    group.stack.pop();
14374                }
14375            } else {
14376                final_selections.push(selection);
14377            }
14378        }
14379
14380        self.change_selections(Default::default(), window, cx, |s| {
14381            s.select(final_selections);
14382        });
14383
14384        let final_selection_ids: HashSet<_> = self
14385            .selections
14386            .all::<Point>(cx)
14387            .iter()
14388            .map(|s| s.id)
14389            .collect();
14390        state.groups.retain_mut(|group| {
14391            // selections might get merged above so we remove invalid items from stacks
14392            group.stack.retain(|id| final_selection_ids.contains(id));
14393
14394            // single selection in stack can be treated as initial state
14395            group.stack.len() > 1
14396        });
14397
14398        if !state.groups.is_empty() {
14399            self.add_selections_state = Some(state);
14400        }
14401    }
14402
14403    fn select_match_ranges(
14404        &mut self,
14405        range: Range<usize>,
14406        reversed: bool,
14407        replace_newest: bool,
14408        auto_scroll: Option<Autoscroll>,
14409        window: &mut Window,
14410        cx: &mut Context<Editor>,
14411    ) {
14412        self.unfold_ranges(
14413            std::slice::from_ref(&range),
14414            false,
14415            auto_scroll.is_some(),
14416            cx,
14417        );
14418        let effects = if let Some(scroll) = auto_scroll {
14419            SelectionEffects::scroll(scroll)
14420        } else {
14421            SelectionEffects::no_scroll()
14422        };
14423        self.change_selections(effects, window, cx, |s| {
14424            if replace_newest {
14425                s.delete(s.newest_anchor().id);
14426            }
14427            if reversed {
14428                s.insert_range(range.end..range.start);
14429            } else {
14430                s.insert_range(range);
14431            }
14432        });
14433    }
14434
14435    pub fn select_next_match_internal(
14436        &mut self,
14437        display_map: &DisplaySnapshot,
14438        replace_newest: bool,
14439        autoscroll: Option<Autoscroll>,
14440        window: &mut Window,
14441        cx: &mut Context<Self>,
14442    ) -> Result<()> {
14443        let buffer = display_map.buffer_snapshot();
14444        let mut selections = self.selections.all::<usize>(cx);
14445        if let Some(mut select_next_state) = self.select_next_state.take() {
14446            let query = &select_next_state.query;
14447            if !select_next_state.done {
14448                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14449                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14450                let mut next_selected_range = None;
14451
14452                // Collect and sort selection ranges for efficient overlap checking
14453                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14454                selection_ranges.sort_by_key(|r| r.start);
14455
14456                let bytes_after_last_selection =
14457                    buffer.bytes_in_range(last_selection.end..buffer.len());
14458                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14459                let query_matches = query
14460                    .stream_find_iter(bytes_after_last_selection)
14461                    .map(|result| (last_selection.end, result))
14462                    .chain(
14463                        query
14464                            .stream_find_iter(bytes_before_first_selection)
14465                            .map(|result| (0, result)),
14466                    );
14467
14468                for (start_offset, query_match) in query_matches {
14469                    let query_match = query_match.unwrap(); // can only fail due to I/O
14470                    let offset_range =
14471                        start_offset + query_match.start()..start_offset + query_match.end();
14472
14473                    if !select_next_state.wordwise
14474                        || (!buffer.is_inside_word(offset_range.start, None)
14475                            && !buffer.is_inside_word(offset_range.end, None))
14476                    {
14477                        // Use binary search to check for overlap (O(log n))
14478                        let overlaps = selection_ranges
14479                            .binary_search_by(|range| {
14480                                if range.end <= offset_range.start {
14481                                    std::cmp::Ordering::Less
14482                                } else if range.start >= offset_range.end {
14483                                    std::cmp::Ordering::Greater
14484                                } else {
14485                                    std::cmp::Ordering::Equal
14486                                }
14487                            })
14488                            .is_ok();
14489
14490                        if !overlaps {
14491                            next_selected_range = Some(offset_range);
14492                            break;
14493                        }
14494                    }
14495                }
14496
14497                if let Some(next_selected_range) = next_selected_range {
14498                    self.select_match_ranges(
14499                        next_selected_range,
14500                        last_selection.reversed,
14501                        replace_newest,
14502                        autoscroll,
14503                        window,
14504                        cx,
14505                    );
14506                } else {
14507                    select_next_state.done = true;
14508                }
14509            }
14510
14511            self.select_next_state = Some(select_next_state);
14512        } else {
14513            let mut only_carets = true;
14514            let mut same_text_selected = true;
14515            let mut selected_text = None;
14516
14517            let mut selections_iter = selections.iter().peekable();
14518            while let Some(selection) = selections_iter.next() {
14519                if selection.start != selection.end {
14520                    only_carets = false;
14521                }
14522
14523                if same_text_selected {
14524                    if selected_text.is_none() {
14525                        selected_text =
14526                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14527                    }
14528
14529                    if let Some(next_selection) = selections_iter.peek() {
14530                        if next_selection.range().len() == selection.range().len() {
14531                            let next_selected_text = buffer
14532                                .text_for_range(next_selection.range())
14533                                .collect::<String>();
14534                            if Some(next_selected_text) != selected_text {
14535                                same_text_selected = false;
14536                                selected_text = None;
14537                            }
14538                        } else {
14539                            same_text_selected = false;
14540                            selected_text = None;
14541                        }
14542                    }
14543                }
14544            }
14545
14546            if only_carets {
14547                for selection in &mut selections {
14548                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14549                    selection.start = word_range.start;
14550                    selection.end = word_range.end;
14551                    selection.goal = SelectionGoal::None;
14552                    selection.reversed = false;
14553                    self.select_match_ranges(
14554                        selection.start..selection.end,
14555                        selection.reversed,
14556                        replace_newest,
14557                        autoscroll,
14558                        window,
14559                        cx,
14560                    );
14561                }
14562
14563                if selections.len() == 1 {
14564                    let selection = selections
14565                        .last()
14566                        .expect("ensured that there's only one selection");
14567                    let query = buffer
14568                        .text_for_range(selection.start..selection.end)
14569                        .collect::<String>();
14570                    let is_empty = query.is_empty();
14571                    let select_state = SelectNextState {
14572                        query: AhoCorasick::new(&[query])?,
14573                        wordwise: true,
14574                        done: is_empty,
14575                    };
14576                    self.select_next_state = Some(select_state);
14577                } else {
14578                    self.select_next_state = None;
14579                }
14580            } else if let Some(selected_text) = selected_text {
14581                self.select_next_state = Some(SelectNextState {
14582                    query: AhoCorasick::new(&[selected_text])?,
14583                    wordwise: false,
14584                    done: false,
14585                });
14586                self.select_next_match_internal(
14587                    display_map,
14588                    replace_newest,
14589                    autoscroll,
14590                    window,
14591                    cx,
14592                )?;
14593            }
14594        }
14595        Ok(())
14596    }
14597
14598    pub fn select_all_matches(
14599        &mut self,
14600        _action: &SelectAllMatches,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) -> Result<()> {
14604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14605
14606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14607
14608        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14609        let Some(select_next_state) = self.select_next_state.as_mut() else {
14610            return Ok(());
14611        };
14612        if select_next_state.done {
14613            return Ok(());
14614        }
14615
14616        let mut new_selections = Vec::new();
14617
14618        let reversed = self.selections.oldest::<usize>(cx).reversed;
14619        let buffer = display_map.buffer_snapshot();
14620        let query_matches = select_next_state
14621            .query
14622            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14623
14624        for query_match in query_matches.into_iter() {
14625            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14626            let offset_range = if reversed {
14627                query_match.end()..query_match.start()
14628            } else {
14629                query_match.start()..query_match.end()
14630            };
14631
14632            if !select_next_state.wordwise
14633                || (!buffer.is_inside_word(offset_range.start, None)
14634                    && !buffer.is_inside_word(offset_range.end, None))
14635            {
14636                new_selections.push(offset_range.start..offset_range.end);
14637            }
14638        }
14639
14640        select_next_state.done = true;
14641
14642        if new_selections.is_empty() {
14643            log::error!("bug: new_selections is empty in select_all_matches");
14644            return Ok(());
14645        }
14646
14647        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14648        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14649            selections.select_ranges(new_selections)
14650        });
14651
14652        Ok(())
14653    }
14654
14655    pub fn select_next(
14656        &mut self,
14657        action: &SelectNext,
14658        window: &mut Window,
14659        cx: &mut Context<Self>,
14660    ) -> Result<()> {
14661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14663        self.select_next_match_internal(
14664            &display_map,
14665            action.replace_newest,
14666            Some(Autoscroll::newest()),
14667            window,
14668            cx,
14669        )?;
14670        Ok(())
14671    }
14672
14673    pub fn select_previous(
14674        &mut self,
14675        action: &SelectPrevious,
14676        window: &mut Window,
14677        cx: &mut Context<Self>,
14678    ) -> Result<()> {
14679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14681        let buffer = display_map.buffer_snapshot();
14682        let mut selections = self.selections.all::<usize>(cx);
14683        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14684            let query = &select_prev_state.query;
14685            if !select_prev_state.done {
14686                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14687                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14688                let mut next_selected_range = None;
14689                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14690                let bytes_before_last_selection =
14691                    buffer.reversed_bytes_in_range(0..last_selection.start);
14692                let bytes_after_first_selection =
14693                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14694                let query_matches = query
14695                    .stream_find_iter(bytes_before_last_selection)
14696                    .map(|result| (last_selection.start, result))
14697                    .chain(
14698                        query
14699                            .stream_find_iter(bytes_after_first_selection)
14700                            .map(|result| (buffer.len(), result)),
14701                    );
14702                for (end_offset, query_match) in query_matches {
14703                    let query_match = query_match.unwrap(); // can only fail due to I/O
14704                    let offset_range =
14705                        end_offset - query_match.end()..end_offset - query_match.start();
14706
14707                    if !select_prev_state.wordwise
14708                        || (!buffer.is_inside_word(offset_range.start, None)
14709                            && !buffer.is_inside_word(offset_range.end, None))
14710                    {
14711                        next_selected_range = Some(offset_range);
14712                        break;
14713                    }
14714                }
14715
14716                if let Some(next_selected_range) = next_selected_range {
14717                    self.select_match_ranges(
14718                        next_selected_range,
14719                        last_selection.reversed,
14720                        action.replace_newest,
14721                        Some(Autoscroll::newest()),
14722                        window,
14723                        cx,
14724                    );
14725                } else {
14726                    select_prev_state.done = true;
14727                }
14728            }
14729
14730            self.select_prev_state = Some(select_prev_state);
14731        } else {
14732            let mut only_carets = true;
14733            let mut same_text_selected = true;
14734            let mut selected_text = None;
14735
14736            let mut selections_iter = selections.iter().peekable();
14737            while let Some(selection) = selections_iter.next() {
14738                if selection.start != selection.end {
14739                    only_carets = false;
14740                }
14741
14742                if same_text_selected {
14743                    if selected_text.is_none() {
14744                        selected_text =
14745                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14746                    }
14747
14748                    if let Some(next_selection) = selections_iter.peek() {
14749                        if next_selection.range().len() == selection.range().len() {
14750                            let next_selected_text = buffer
14751                                .text_for_range(next_selection.range())
14752                                .collect::<String>();
14753                            if Some(next_selected_text) != selected_text {
14754                                same_text_selected = false;
14755                                selected_text = None;
14756                            }
14757                        } else {
14758                            same_text_selected = false;
14759                            selected_text = None;
14760                        }
14761                    }
14762                }
14763            }
14764
14765            if only_carets {
14766                for selection in &mut selections {
14767                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14768                    selection.start = word_range.start;
14769                    selection.end = word_range.end;
14770                    selection.goal = SelectionGoal::None;
14771                    selection.reversed = false;
14772                    self.select_match_ranges(
14773                        selection.start..selection.end,
14774                        selection.reversed,
14775                        action.replace_newest,
14776                        Some(Autoscroll::newest()),
14777                        window,
14778                        cx,
14779                    );
14780                }
14781                if selections.len() == 1 {
14782                    let selection = selections
14783                        .last()
14784                        .expect("ensured that there's only one selection");
14785                    let query = buffer
14786                        .text_for_range(selection.start..selection.end)
14787                        .collect::<String>();
14788                    let is_empty = query.is_empty();
14789                    let select_state = SelectNextState {
14790                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14791                        wordwise: true,
14792                        done: is_empty,
14793                    };
14794                    self.select_prev_state = Some(select_state);
14795                } else {
14796                    self.select_prev_state = None;
14797                }
14798            } else if let Some(selected_text) = selected_text {
14799                self.select_prev_state = Some(SelectNextState {
14800                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14801                    wordwise: false,
14802                    done: false,
14803                });
14804                self.select_previous(action, window, cx)?;
14805            }
14806        }
14807        Ok(())
14808    }
14809
14810    pub fn find_next_match(
14811        &mut self,
14812        _: &FindNextMatch,
14813        window: &mut Window,
14814        cx: &mut Context<Self>,
14815    ) -> Result<()> {
14816        let selections = self.selections.disjoint_anchors_arc();
14817        match selections.first() {
14818            Some(first) if selections.len() >= 2 => {
14819                self.change_selections(Default::default(), window, cx, |s| {
14820                    s.select_ranges([first.range()]);
14821                });
14822            }
14823            _ => self.select_next(
14824                &SelectNext {
14825                    replace_newest: true,
14826                },
14827                window,
14828                cx,
14829            )?,
14830        }
14831        Ok(())
14832    }
14833
14834    pub fn find_previous_match(
14835        &mut self,
14836        _: &FindPreviousMatch,
14837        window: &mut Window,
14838        cx: &mut Context<Self>,
14839    ) -> Result<()> {
14840        let selections = self.selections.disjoint_anchors_arc();
14841        match selections.last() {
14842            Some(last) if selections.len() >= 2 => {
14843                self.change_selections(Default::default(), window, cx, |s| {
14844                    s.select_ranges([last.range()]);
14845                });
14846            }
14847            _ => self.select_previous(
14848                &SelectPrevious {
14849                    replace_newest: true,
14850                },
14851                window,
14852                cx,
14853            )?,
14854        }
14855        Ok(())
14856    }
14857
14858    pub fn toggle_comments(
14859        &mut self,
14860        action: &ToggleComments,
14861        window: &mut Window,
14862        cx: &mut Context<Self>,
14863    ) {
14864        if self.read_only(cx) {
14865            return;
14866        }
14867        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14868        let text_layout_details = &self.text_layout_details(window);
14869        self.transact(window, cx, |this, window, cx| {
14870            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14871            let mut edits = Vec::new();
14872            let mut selection_edit_ranges = Vec::new();
14873            let mut last_toggled_row = None;
14874            let snapshot = this.buffer.read(cx).read(cx);
14875            let empty_str: Arc<str> = Arc::default();
14876            let mut suffixes_inserted = Vec::new();
14877            let ignore_indent = action.ignore_indent;
14878
14879            fn comment_prefix_range(
14880                snapshot: &MultiBufferSnapshot,
14881                row: MultiBufferRow,
14882                comment_prefix: &str,
14883                comment_prefix_whitespace: &str,
14884                ignore_indent: bool,
14885            ) -> Range<Point> {
14886                let indent_size = if ignore_indent {
14887                    0
14888                } else {
14889                    snapshot.indent_size_for_line(row).len
14890                };
14891
14892                let start = Point::new(row.0, indent_size);
14893
14894                let mut line_bytes = snapshot
14895                    .bytes_in_range(start..snapshot.max_point())
14896                    .flatten()
14897                    .copied();
14898
14899                // If this line currently begins with the line comment prefix, then record
14900                // the range containing the prefix.
14901                if line_bytes
14902                    .by_ref()
14903                    .take(comment_prefix.len())
14904                    .eq(comment_prefix.bytes())
14905                {
14906                    // Include any whitespace that matches the comment prefix.
14907                    let matching_whitespace_len = line_bytes
14908                        .zip(comment_prefix_whitespace.bytes())
14909                        .take_while(|(a, b)| a == b)
14910                        .count() as u32;
14911                    let end = Point::new(
14912                        start.row,
14913                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14914                    );
14915                    start..end
14916                } else {
14917                    start..start
14918                }
14919            }
14920
14921            fn comment_suffix_range(
14922                snapshot: &MultiBufferSnapshot,
14923                row: MultiBufferRow,
14924                comment_suffix: &str,
14925                comment_suffix_has_leading_space: bool,
14926            ) -> Range<Point> {
14927                let end = Point::new(row.0, snapshot.line_len(row));
14928                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14929
14930                let mut line_end_bytes = snapshot
14931                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14932                    .flatten()
14933                    .copied();
14934
14935                let leading_space_len = if suffix_start_column > 0
14936                    && line_end_bytes.next() == Some(b' ')
14937                    && comment_suffix_has_leading_space
14938                {
14939                    1
14940                } else {
14941                    0
14942                };
14943
14944                // If this line currently begins with the line comment prefix, then record
14945                // the range containing the prefix.
14946                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14947                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14948                    start..end
14949                } else {
14950                    end..end
14951                }
14952            }
14953
14954            // TODO: Handle selections that cross excerpts
14955            for selection in &mut selections {
14956                let start_column = snapshot
14957                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14958                    .len;
14959                let language = if let Some(language) =
14960                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14961                {
14962                    language
14963                } else {
14964                    continue;
14965                };
14966
14967                selection_edit_ranges.clear();
14968
14969                // If multiple selections contain a given row, avoid processing that
14970                // row more than once.
14971                let mut start_row = MultiBufferRow(selection.start.row);
14972                if last_toggled_row == Some(start_row) {
14973                    start_row = start_row.next_row();
14974                }
14975                let end_row =
14976                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14977                        MultiBufferRow(selection.end.row - 1)
14978                    } else {
14979                        MultiBufferRow(selection.end.row)
14980                    };
14981                last_toggled_row = Some(end_row);
14982
14983                if start_row > end_row {
14984                    continue;
14985                }
14986
14987                // If the language has line comments, toggle those.
14988                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14989
14990                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14991                if ignore_indent {
14992                    full_comment_prefixes = full_comment_prefixes
14993                        .into_iter()
14994                        .map(|s| Arc::from(s.trim_end()))
14995                        .collect();
14996                }
14997
14998                if !full_comment_prefixes.is_empty() {
14999                    let first_prefix = full_comment_prefixes
15000                        .first()
15001                        .expect("prefixes is non-empty");
15002                    let prefix_trimmed_lengths = full_comment_prefixes
15003                        .iter()
15004                        .map(|p| p.trim_end_matches(' ').len())
15005                        .collect::<SmallVec<[usize; 4]>>();
15006
15007                    let mut all_selection_lines_are_comments = true;
15008
15009                    for row in start_row.0..=end_row.0 {
15010                        let row = MultiBufferRow(row);
15011                        if start_row < end_row && snapshot.is_line_blank(row) {
15012                            continue;
15013                        }
15014
15015                        let prefix_range = full_comment_prefixes
15016                            .iter()
15017                            .zip(prefix_trimmed_lengths.iter().copied())
15018                            .map(|(prefix, trimmed_prefix_len)| {
15019                                comment_prefix_range(
15020                                    snapshot.deref(),
15021                                    row,
15022                                    &prefix[..trimmed_prefix_len],
15023                                    &prefix[trimmed_prefix_len..],
15024                                    ignore_indent,
15025                                )
15026                            })
15027                            .max_by_key(|range| range.end.column - range.start.column)
15028                            .expect("prefixes is non-empty");
15029
15030                        if prefix_range.is_empty() {
15031                            all_selection_lines_are_comments = false;
15032                        }
15033
15034                        selection_edit_ranges.push(prefix_range);
15035                    }
15036
15037                    if all_selection_lines_are_comments {
15038                        edits.extend(
15039                            selection_edit_ranges
15040                                .iter()
15041                                .cloned()
15042                                .map(|range| (range, empty_str.clone())),
15043                        );
15044                    } else {
15045                        let min_column = selection_edit_ranges
15046                            .iter()
15047                            .map(|range| range.start.column)
15048                            .min()
15049                            .unwrap_or(0);
15050                        edits.extend(selection_edit_ranges.iter().map(|range| {
15051                            let position = Point::new(range.start.row, min_column);
15052                            (position..position, first_prefix.clone())
15053                        }));
15054                    }
15055                } else if let Some(BlockCommentConfig {
15056                    start: full_comment_prefix,
15057                    end: comment_suffix,
15058                    ..
15059                }) = language.block_comment()
15060                {
15061                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15062                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15063                    let prefix_range = comment_prefix_range(
15064                        snapshot.deref(),
15065                        start_row,
15066                        comment_prefix,
15067                        comment_prefix_whitespace,
15068                        ignore_indent,
15069                    );
15070                    let suffix_range = comment_suffix_range(
15071                        snapshot.deref(),
15072                        end_row,
15073                        comment_suffix.trim_start_matches(' '),
15074                        comment_suffix.starts_with(' '),
15075                    );
15076
15077                    if prefix_range.is_empty() || suffix_range.is_empty() {
15078                        edits.push((
15079                            prefix_range.start..prefix_range.start,
15080                            full_comment_prefix.clone(),
15081                        ));
15082                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15083                        suffixes_inserted.push((end_row, comment_suffix.len()));
15084                    } else {
15085                        edits.push((prefix_range, empty_str.clone()));
15086                        edits.push((suffix_range, empty_str.clone()));
15087                    }
15088                } else {
15089                    continue;
15090                }
15091            }
15092
15093            drop(snapshot);
15094            this.buffer.update(cx, |buffer, cx| {
15095                buffer.edit(edits, None, cx);
15096            });
15097
15098            // Adjust selections so that they end before any comment suffixes that
15099            // were inserted.
15100            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15101            let mut selections = this.selections.all::<Point>(cx);
15102            let snapshot = this.buffer.read(cx).read(cx);
15103            for selection in &mut selections {
15104                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15105                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15106                        Ordering::Less => {
15107                            suffixes_inserted.next();
15108                            continue;
15109                        }
15110                        Ordering::Greater => break,
15111                        Ordering::Equal => {
15112                            if selection.end.column == snapshot.line_len(row) {
15113                                if selection.is_empty() {
15114                                    selection.start.column -= suffix_len as u32;
15115                                }
15116                                selection.end.column -= suffix_len as u32;
15117                            }
15118                            break;
15119                        }
15120                    }
15121                }
15122            }
15123
15124            drop(snapshot);
15125            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15126
15127            let selections = this.selections.all::<Point>(cx);
15128            let selections_on_single_row = selections.windows(2).all(|selections| {
15129                selections[0].start.row == selections[1].start.row
15130                    && selections[0].end.row == selections[1].end.row
15131                    && selections[0].start.row == selections[0].end.row
15132            });
15133            let selections_selecting = selections
15134                .iter()
15135                .any(|selection| selection.start != selection.end);
15136            let advance_downwards = action.advance_downwards
15137                && selections_on_single_row
15138                && !selections_selecting
15139                && !matches!(this.mode, EditorMode::SingleLine);
15140
15141            if advance_downwards {
15142                let snapshot = this.buffer.read(cx).snapshot(cx);
15143
15144                this.change_selections(Default::default(), window, cx, |s| {
15145                    s.move_cursors_with(|display_snapshot, display_point, _| {
15146                        let mut point = display_point.to_point(display_snapshot);
15147                        point.row += 1;
15148                        point = snapshot.clip_point(point, Bias::Left);
15149                        let display_point = point.to_display_point(display_snapshot);
15150                        let goal = SelectionGoal::HorizontalPosition(
15151                            display_snapshot
15152                                .x_for_display_point(display_point, text_layout_details)
15153                                .into(),
15154                        );
15155                        (display_point, goal)
15156                    })
15157                });
15158            }
15159        });
15160    }
15161
15162    pub fn select_enclosing_symbol(
15163        &mut self,
15164        _: &SelectEnclosingSymbol,
15165        window: &mut Window,
15166        cx: &mut Context<Self>,
15167    ) {
15168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15169
15170        let buffer = self.buffer.read(cx).snapshot(cx);
15171        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15172
15173        fn update_selection(
15174            selection: &Selection<usize>,
15175            buffer_snap: &MultiBufferSnapshot,
15176        ) -> Option<Selection<usize>> {
15177            let cursor = selection.head();
15178            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15179            for symbol in symbols.iter().rev() {
15180                let start = symbol.range.start.to_offset(buffer_snap);
15181                let end = symbol.range.end.to_offset(buffer_snap);
15182                let new_range = start..end;
15183                if start < selection.start || end > selection.end {
15184                    return Some(Selection {
15185                        id: selection.id,
15186                        start: new_range.start,
15187                        end: new_range.end,
15188                        goal: SelectionGoal::None,
15189                        reversed: selection.reversed,
15190                    });
15191                }
15192            }
15193            None
15194        }
15195
15196        let mut selected_larger_symbol = false;
15197        let new_selections = old_selections
15198            .iter()
15199            .map(|selection| match update_selection(selection, &buffer) {
15200                Some(new_selection) => {
15201                    if new_selection.range() != selection.range() {
15202                        selected_larger_symbol = true;
15203                    }
15204                    new_selection
15205                }
15206                None => selection.clone(),
15207            })
15208            .collect::<Vec<_>>();
15209
15210        if selected_larger_symbol {
15211            self.change_selections(Default::default(), window, cx, |s| {
15212                s.select(new_selections);
15213            });
15214        }
15215    }
15216
15217    pub fn select_larger_syntax_node(
15218        &mut self,
15219        _: &SelectLargerSyntaxNode,
15220        window: &mut Window,
15221        cx: &mut Context<Self>,
15222    ) {
15223        let Some(visible_row_count) = self.visible_row_count() else {
15224            return;
15225        };
15226        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15227        if old_selections.is_empty() {
15228            return;
15229        }
15230
15231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15232
15233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15234        let buffer = self.buffer.read(cx).snapshot(cx);
15235
15236        let mut selected_larger_node = false;
15237        let mut new_selections = old_selections
15238            .iter()
15239            .map(|selection| {
15240                let old_range = selection.start..selection.end;
15241
15242                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15243                    // manually select word at selection
15244                    if ["string_content", "inline"].contains(&node.kind()) {
15245                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15246                        // ignore if word is already selected
15247                        if !word_range.is_empty() && old_range != word_range {
15248                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15249                            // only select word if start and end point belongs to same word
15250                            if word_range == last_word_range {
15251                                selected_larger_node = true;
15252                                return Selection {
15253                                    id: selection.id,
15254                                    start: word_range.start,
15255                                    end: word_range.end,
15256                                    goal: SelectionGoal::None,
15257                                    reversed: selection.reversed,
15258                                };
15259                            }
15260                        }
15261                    }
15262                }
15263
15264                let mut new_range = old_range.clone();
15265                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15266                    new_range = range;
15267                    if !node.is_named() {
15268                        continue;
15269                    }
15270                    if !display_map.intersects_fold(new_range.start)
15271                        && !display_map.intersects_fold(new_range.end)
15272                    {
15273                        break;
15274                    }
15275                }
15276
15277                selected_larger_node |= new_range != old_range;
15278                Selection {
15279                    id: selection.id,
15280                    start: new_range.start,
15281                    end: new_range.end,
15282                    goal: SelectionGoal::None,
15283                    reversed: selection.reversed,
15284                }
15285            })
15286            .collect::<Vec<_>>();
15287
15288        if !selected_larger_node {
15289            return; // don't put this call in the history
15290        }
15291
15292        // scroll based on transformation done to the last selection created by the user
15293        let (last_old, last_new) = old_selections
15294            .last()
15295            .zip(new_selections.last().cloned())
15296            .expect("old_selections isn't empty");
15297
15298        // revert selection
15299        let is_selection_reversed = {
15300            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15301            new_selections.last_mut().expect("checked above").reversed =
15302                should_newest_selection_be_reversed;
15303            should_newest_selection_be_reversed
15304        };
15305
15306        if selected_larger_node {
15307            self.select_syntax_node_history.disable_clearing = true;
15308            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15309                s.select(new_selections.clone());
15310            });
15311            self.select_syntax_node_history.disable_clearing = false;
15312        }
15313
15314        let start_row = last_new.start.to_display_point(&display_map).row().0;
15315        let end_row = last_new.end.to_display_point(&display_map).row().0;
15316        let selection_height = end_row - start_row + 1;
15317        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15318
15319        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15320        let scroll_behavior = if fits_on_the_screen {
15321            self.request_autoscroll(Autoscroll::fit(), cx);
15322            SelectSyntaxNodeScrollBehavior::FitSelection
15323        } else if is_selection_reversed {
15324            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15325            SelectSyntaxNodeScrollBehavior::CursorTop
15326        } else {
15327            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15328            SelectSyntaxNodeScrollBehavior::CursorBottom
15329        };
15330
15331        self.select_syntax_node_history.push((
15332            old_selections,
15333            scroll_behavior,
15334            is_selection_reversed,
15335        ));
15336    }
15337
15338    pub fn select_smaller_syntax_node(
15339        &mut self,
15340        _: &SelectSmallerSyntaxNode,
15341        window: &mut Window,
15342        cx: &mut Context<Self>,
15343    ) {
15344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15345
15346        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15347            self.select_syntax_node_history.pop()
15348        {
15349            if let Some(selection) = selections.last_mut() {
15350                selection.reversed = is_selection_reversed;
15351            }
15352
15353            self.select_syntax_node_history.disable_clearing = true;
15354            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15355                s.select(selections.to_vec());
15356            });
15357            self.select_syntax_node_history.disable_clearing = false;
15358
15359            match scroll_behavior {
15360                SelectSyntaxNodeScrollBehavior::CursorTop => {
15361                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15362                }
15363                SelectSyntaxNodeScrollBehavior::FitSelection => {
15364                    self.request_autoscroll(Autoscroll::fit(), cx);
15365                }
15366                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15367                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15368                }
15369            }
15370        }
15371    }
15372
15373    pub fn unwrap_syntax_node(
15374        &mut self,
15375        _: &UnwrapSyntaxNode,
15376        window: &mut Window,
15377        cx: &mut Context<Self>,
15378    ) {
15379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15380
15381        let buffer = self.buffer.read(cx).snapshot(cx);
15382        let selections = self
15383            .selections
15384            .all::<usize>(cx)
15385            .into_iter()
15386            // subtracting the offset requires sorting
15387            .sorted_by_key(|i| i.start);
15388
15389        let full_edits = selections
15390            .into_iter()
15391            .filter_map(|selection| {
15392                let child = if selection.is_empty()
15393                    && let Some((_, ancestor_range)) =
15394                        buffer.syntax_ancestor(selection.start..selection.end)
15395                {
15396                    ancestor_range
15397                } else {
15398                    selection.range()
15399                };
15400
15401                let mut parent = child.clone();
15402                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15403                    parent = ancestor_range;
15404                    if parent.start < child.start || parent.end > child.end {
15405                        break;
15406                    }
15407                }
15408
15409                if parent == child {
15410                    return None;
15411                }
15412                let text = buffer.text_for_range(child).collect::<String>();
15413                Some((selection.id, parent, text))
15414            })
15415            .collect::<Vec<_>>();
15416        if full_edits.is_empty() {
15417            return;
15418        }
15419
15420        self.transact(window, cx, |this, window, cx| {
15421            this.buffer.update(cx, |buffer, cx| {
15422                buffer.edit(
15423                    full_edits
15424                        .iter()
15425                        .map(|(_, p, t)| (p.clone(), t.clone()))
15426                        .collect::<Vec<_>>(),
15427                    None,
15428                    cx,
15429                );
15430            });
15431            this.change_selections(Default::default(), window, cx, |s| {
15432                let mut offset = 0;
15433                let mut selections = vec![];
15434                for (id, parent, text) in full_edits {
15435                    let start = parent.start - offset;
15436                    offset += parent.len() - text.len();
15437                    selections.push(Selection {
15438                        id,
15439                        start,
15440                        end: start + text.len(),
15441                        reversed: false,
15442                        goal: Default::default(),
15443                    });
15444                }
15445                s.select(selections);
15446            });
15447        });
15448    }
15449
15450    pub fn select_next_syntax_node(
15451        &mut self,
15452        _: &SelectNextSyntaxNode,
15453        window: &mut Window,
15454        cx: &mut Context<Self>,
15455    ) {
15456        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15457        if old_selections.is_empty() {
15458            return;
15459        }
15460
15461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15462
15463        let buffer = self.buffer.read(cx).snapshot(cx);
15464        let mut selected_sibling = false;
15465
15466        let new_selections = old_selections
15467            .iter()
15468            .map(|selection| {
15469                let old_range = selection.start..selection.end;
15470
15471                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15472                    let new_range = node.byte_range();
15473                    selected_sibling = true;
15474                    Selection {
15475                        id: selection.id,
15476                        start: new_range.start,
15477                        end: new_range.end,
15478                        goal: SelectionGoal::None,
15479                        reversed: selection.reversed,
15480                    }
15481                } else {
15482                    selection.clone()
15483                }
15484            })
15485            .collect::<Vec<_>>();
15486
15487        if selected_sibling {
15488            self.change_selections(
15489                SelectionEffects::scroll(Autoscroll::fit()),
15490                window,
15491                cx,
15492                |s| {
15493                    s.select(new_selections);
15494                },
15495            );
15496        }
15497    }
15498
15499    pub fn select_prev_syntax_node(
15500        &mut self,
15501        _: &SelectPreviousSyntaxNode,
15502        window: &mut Window,
15503        cx: &mut Context<Self>,
15504    ) {
15505        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15506        if old_selections.is_empty() {
15507            return;
15508        }
15509
15510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15511
15512        let buffer = self.buffer.read(cx).snapshot(cx);
15513        let mut selected_sibling = false;
15514
15515        let new_selections = old_selections
15516            .iter()
15517            .map(|selection| {
15518                let old_range = selection.start..selection.end;
15519
15520                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15521                    let new_range = node.byte_range();
15522                    selected_sibling = true;
15523                    Selection {
15524                        id: selection.id,
15525                        start: new_range.start,
15526                        end: new_range.end,
15527                        goal: SelectionGoal::None,
15528                        reversed: selection.reversed,
15529                    }
15530                } else {
15531                    selection.clone()
15532                }
15533            })
15534            .collect::<Vec<_>>();
15535
15536        if selected_sibling {
15537            self.change_selections(
15538                SelectionEffects::scroll(Autoscroll::fit()),
15539                window,
15540                cx,
15541                |s| {
15542                    s.select(new_selections);
15543                },
15544            );
15545        }
15546    }
15547
15548    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15549        if !EditorSettings::get_global(cx).gutter.runnables {
15550            self.clear_tasks();
15551            return Task::ready(());
15552        }
15553        let project = self.project().map(Entity::downgrade);
15554        let task_sources = self.lsp_task_sources(cx);
15555        let multi_buffer = self.buffer.downgrade();
15556        cx.spawn_in(window, async move |editor, cx| {
15557            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15558            let Some(project) = project.and_then(|p| p.upgrade()) else {
15559                return;
15560            };
15561            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15562                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15563            }) else {
15564                return;
15565            };
15566
15567            let hide_runnables = project
15568                .update(cx, |project, _| project.is_via_collab())
15569                .unwrap_or(true);
15570            if hide_runnables {
15571                return;
15572            }
15573            let new_rows =
15574                cx.background_spawn({
15575                    let snapshot = display_snapshot.clone();
15576                    async move {
15577                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15578                    }
15579                })
15580                    .await;
15581            let Ok(lsp_tasks) =
15582                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15583            else {
15584                return;
15585            };
15586            let lsp_tasks = lsp_tasks.await;
15587
15588            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15589                lsp_tasks
15590                    .into_iter()
15591                    .flat_map(|(kind, tasks)| {
15592                        tasks.into_iter().filter_map(move |(location, task)| {
15593                            Some((kind.clone(), location?, task))
15594                        })
15595                    })
15596                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15597                        let buffer = location.target.buffer;
15598                        let buffer_snapshot = buffer.read(cx).snapshot();
15599                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15600                            |(excerpt_id, snapshot, _)| {
15601                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15602                                    display_snapshot
15603                                        .buffer_snapshot()
15604                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15605                                } else {
15606                                    None
15607                                }
15608                            },
15609                        );
15610                        if let Some(offset) = offset {
15611                            let task_buffer_range =
15612                                location.target.range.to_point(&buffer_snapshot);
15613                            let context_buffer_range =
15614                                task_buffer_range.to_offset(&buffer_snapshot);
15615                            let context_range = BufferOffset(context_buffer_range.start)
15616                                ..BufferOffset(context_buffer_range.end);
15617
15618                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15619                                .or_insert_with(|| RunnableTasks {
15620                                    templates: Vec::new(),
15621                                    offset,
15622                                    column: task_buffer_range.start.column,
15623                                    extra_variables: HashMap::default(),
15624                                    context_range,
15625                                })
15626                                .templates
15627                                .push((kind, task.original_task().clone()));
15628                        }
15629
15630                        acc
15631                    })
15632            }) else {
15633                return;
15634            };
15635
15636            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15637                buffer.language_settings(cx).tasks.prefer_lsp
15638            }) else {
15639                return;
15640            };
15641
15642            let rows = Self::runnable_rows(
15643                project,
15644                display_snapshot,
15645                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15646                new_rows,
15647                cx.clone(),
15648            )
15649            .await;
15650            editor
15651                .update(cx, |editor, _| {
15652                    editor.clear_tasks();
15653                    for (key, mut value) in rows {
15654                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15655                            value.templates.extend(lsp_tasks.templates);
15656                        }
15657
15658                        editor.insert_tasks(key, value);
15659                    }
15660                    for (key, value) in lsp_tasks_by_rows {
15661                        editor.insert_tasks(key, value);
15662                    }
15663                })
15664                .ok();
15665        })
15666    }
15667    fn fetch_runnable_ranges(
15668        snapshot: &DisplaySnapshot,
15669        range: Range<Anchor>,
15670    ) -> Vec<language::RunnableRange> {
15671        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15672    }
15673
15674    fn runnable_rows(
15675        project: Entity<Project>,
15676        snapshot: DisplaySnapshot,
15677        prefer_lsp: bool,
15678        runnable_ranges: Vec<RunnableRange>,
15679        cx: AsyncWindowContext,
15680    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15681        cx.spawn(async move |cx| {
15682            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15683            for mut runnable in runnable_ranges {
15684                let Some(tasks) = cx
15685                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15686                    .ok()
15687                else {
15688                    continue;
15689                };
15690                let mut tasks = tasks.await;
15691
15692                if prefer_lsp {
15693                    tasks.retain(|(task_kind, _)| {
15694                        !matches!(task_kind, TaskSourceKind::Language { .. })
15695                    });
15696                }
15697                if tasks.is_empty() {
15698                    continue;
15699                }
15700
15701                let point = runnable
15702                    .run_range
15703                    .start
15704                    .to_point(&snapshot.buffer_snapshot());
15705                let Some(row) = snapshot
15706                    .buffer_snapshot()
15707                    .buffer_line_for_row(MultiBufferRow(point.row))
15708                    .map(|(_, range)| range.start.row)
15709                else {
15710                    continue;
15711                };
15712
15713                let context_range =
15714                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15715                runnable_rows.push((
15716                    (runnable.buffer_id, row),
15717                    RunnableTasks {
15718                        templates: tasks,
15719                        offset: snapshot
15720                            .buffer_snapshot()
15721                            .anchor_before(runnable.run_range.start),
15722                        context_range,
15723                        column: point.column,
15724                        extra_variables: runnable.extra_captures,
15725                    },
15726                ));
15727            }
15728            runnable_rows
15729        })
15730    }
15731
15732    fn templates_with_tags(
15733        project: &Entity<Project>,
15734        runnable: &mut Runnable,
15735        cx: &mut App,
15736    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15737        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15738            let (worktree_id, file) = project
15739                .buffer_for_id(runnable.buffer, cx)
15740                .and_then(|buffer| buffer.read(cx).file())
15741                .map(|file| (file.worktree_id(cx), file.clone()))
15742                .unzip();
15743
15744            (
15745                project.task_store().read(cx).task_inventory().cloned(),
15746                worktree_id,
15747                file,
15748            )
15749        });
15750
15751        let tags = mem::take(&mut runnable.tags);
15752        let language = runnable.language.clone();
15753        cx.spawn(async move |cx| {
15754            let mut templates_with_tags = Vec::new();
15755            if let Some(inventory) = inventory {
15756                for RunnableTag(tag) in tags {
15757                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15758                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15759                    }) else {
15760                        return templates_with_tags;
15761                    };
15762                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15763                        move |(_, template)| {
15764                            template.tags.iter().any(|source_tag| source_tag == &tag)
15765                        },
15766                    ));
15767                }
15768            }
15769            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15770
15771            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15772                // Strongest source wins; if we have worktree tag binding, prefer that to
15773                // global and language bindings;
15774                // if we have a global binding, prefer that to language binding.
15775                let first_mismatch = templates_with_tags
15776                    .iter()
15777                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15778                if let Some(index) = first_mismatch {
15779                    templates_with_tags.truncate(index);
15780                }
15781            }
15782
15783            templates_with_tags
15784        })
15785    }
15786
15787    pub fn move_to_enclosing_bracket(
15788        &mut self,
15789        _: &MoveToEnclosingBracket,
15790        window: &mut Window,
15791        cx: &mut Context<Self>,
15792    ) {
15793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15794        self.change_selections(Default::default(), window, cx, |s| {
15795            s.move_offsets_with(|snapshot, selection| {
15796                let Some(enclosing_bracket_ranges) =
15797                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15798                else {
15799                    return;
15800                };
15801
15802                let mut best_length = usize::MAX;
15803                let mut best_inside = false;
15804                let mut best_in_bracket_range = false;
15805                let mut best_destination = None;
15806                for (open, close) in enclosing_bracket_ranges {
15807                    let close = close.to_inclusive();
15808                    let length = close.end() - open.start;
15809                    let inside = selection.start >= open.end && selection.end <= *close.start();
15810                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15811                        || close.contains(&selection.head());
15812
15813                    // If best is next to a bracket and current isn't, skip
15814                    if !in_bracket_range && best_in_bracket_range {
15815                        continue;
15816                    }
15817
15818                    // Prefer smaller lengths unless best is inside and current isn't
15819                    if length > best_length && (best_inside || !inside) {
15820                        continue;
15821                    }
15822
15823                    best_length = length;
15824                    best_inside = inside;
15825                    best_in_bracket_range = in_bracket_range;
15826                    best_destination = Some(
15827                        if close.contains(&selection.start) && close.contains(&selection.end) {
15828                            if inside { open.end } else { open.start }
15829                        } else if inside {
15830                            *close.start()
15831                        } else {
15832                            *close.end()
15833                        },
15834                    );
15835                }
15836
15837                if let Some(destination) = best_destination {
15838                    selection.collapse_to(destination, SelectionGoal::None);
15839                }
15840            })
15841        });
15842    }
15843
15844    pub fn undo_selection(
15845        &mut self,
15846        _: &UndoSelection,
15847        window: &mut Window,
15848        cx: &mut Context<Self>,
15849    ) {
15850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15851        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15852            self.selection_history.mode = SelectionHistoryMode::Undoing;
15853            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15854                this.end_selection(window, cx);
15855                this.change_selections(
15856                    SelectionEffects::scroll(Autoscroll::newest()),
15857                    window,
15858                    cx,
15859                    |s| s.select_anchors(entry.selections.to_vec()),
15860                );
15861            });
15862            self.selection_history.mode = SelectionHistoryMode::Normal;
15863
15864            self.select_next_state = entry.select_next_state;
15865            self.select_prev_state = entry.select_prev_state;
15866            self.add_selections_state = entry.add_selections_state;
15867        }
15868    }
15869
15870    pub fn redo_selection(
15871        &mut self,
15872        _: &RedoSelection,
15873        window: &mut Window,
15874        cx: &mut Context<Self>,
15875    ) {
15876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15877        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15878            self.selection_history.mode = SelectionHistoryMode::Redoing;
15879            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15880                this.end_selection(window, cx);
15881                this.change_selections(
15882                    SelectionEffects::scroll(Autoscroll::newest()),
15883                    window,
15884                    cx,
15885                    |s| s.select_anchors(entry.selections.to_vec()),
15886                );
15887            });
15888            self.selection_history.mode = SelectionHistoryMode::Normal;
15889
15890            self.select_next_state = entry.select_next_state;
15891            self.select_prev_state = entry.select_prev_state;
15892            self.add_selections_state = entry.add_selections_state;
15893        }
15894    }
15895
15896    pub fn expand_excerpts(
15897        &mut self,
15898        action: &ExpandExcerpts,
15899        _: &mut Window,
15900        cx: &mut Context<Self>,
15901    ) {
15902        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15903    }
15904
15905    pub fn expand_excerpts_down(
15906        &mut self,
15907        action: &ExpandExcerptsDown,
15908        _: &mut Window,
15909        cx: &mut Context<Self>,
15910    ) {
15911        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15912    }
15913
15914    pub fn expand_excerpts_up(
15915        &mut self,
15916        action: &ExpandExcerptsUp,
15917        _: &mut Window,
15918        cx: &mut Context<Self>,
15919    ) {
15920        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15921    }
15922
15923    pub fn expand_excerpts_for_direction(
15924        &mut self,
15925        lines: u32,
15926        direction: ExpandExcerptDirection,
15927
15928        cx: &mut Context<Self>,
15929    ) {
15930        let selections = self.selections.disjoint_anchors_arc();
15931
15932        let lines = if lines == 0 {
15933            EditorSettings::get_global(cx).expand_excerpt_lines
15934        } else {
15935            lines
15936        };
15937
15938        self.buffer.update(cx, |buffer, cx| {
15939            let snapshot = buffer.snapshot(cx);
15940            let mut excerpt_ids = selections
15941                .iter()
15942                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15943                .collect::<Vec<_>>();
15944            excerpt_ids.sort();
15945            excerpt_ids.dedup();
15946            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15947        })
15948    }
15949
15950    pub fn expand_excerpt(
15951        &mut self,
15952        excerpt: ExcerptId,
15953        direction: ExpandExcerptDirection,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        let current_scroll_position = self.scroll_position(cx);
15958        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15959        let mut should_scroll_up = false;
15960
15961        if direction == ExpandExcerptDirection::Down {
15962            let multi_buffer = self.buffer.read(cx);
15963            let snapshot = multi_buffer.snapshot(cx);
15964            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15965                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15966                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15967            {
15968                let buffer_snapshot = buffer.read(cx).snapshot();
15969                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15970                let last_row = buffer_snapshot.max_point().row;
15971                let lines_below = last_row.saturating_sub(excerpt_end_row);
15972                should_scroll_up = lines_below >= lines_to_expand;
15973            }
15974        }
15975
15976        self.buffer.update(cx, |buffer, cx| {
15977            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15978        });
15979
15980        if should_scroll_up {
15981            let new_scroll_position =
15982                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15983            self.set_scroll_position(new_scroll_position, window, cx);
15984        }
15985    }
15986
15987    pub fn go_to_singleton_buffer_point(
15988        &mut self,
15989        point: Point,
15990        window: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        self.go_to_singleton_buffer_range(point..point, window, cx);
15994    }
15995
15996    pub fn go_to_singleton_buffer_range(
15997        &mut self,
15998        range: Range<Point>,
15999        window: &mut Window,
16000        cx: &mut Context<Self>,
16001    ) {
16002        let multibuffer = self.buffer().read(cx);
16003        let Some(buffer) = multibuffer.as_singleton() else {
16004            return;
16005        };
16006        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16007            return;
16008        };
16009        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16010            return;
16011        };
16012        self.change_selections(
16013            SelectionEffects::default().nav_history(true),
16014            window,
16015            cx,
16016            |s| s.select_anchor_ranges([start..end]),
16017        );
16018    }
16019
16020    pub fn go_to_diagnostic(
16021        &mut self,
16022        action: &GoToDiagnostic,
16023        window: &mut Window,
16024        cx: &mut Context<Self>,
16025    ) {
16026        if !self.diagnostics_enabled() {
16027            return;
16028        }
16029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16030        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16031    }
16032
16033    pub fn go_to_prev_diagnostic(
16034        &mut self,
16035        action: &GoToPreviousDiagnostic,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        if !self.diagnostics_enabled() {
16040            return;
16041        }
16042        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16043        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16044    }
16045
16046    pub fn go_to_diagnostic_impl(
16047        &mut self,
16048        direction: Direction,
16049        severity: GoToDiagnosticSeverityFilter,
16050        window: &mut Window,
16051        cx: &mut Context<Self>,
16052    ) {
16053        let buffer = self.buffer.read(cx).snapshot(cx);
16054        let selection = self.selections.newest::<usize>(cx);
16055
16056        let mut active_group_id = None;
16057        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16058            && active_group.active_range.start.to_offset(&buffer) == selection.start
16059        {
16060            active_group_id = Some(active_group.group_id);
16061        }
16062
16063        fn filtered<'a>(
16064            snapshot: EditorSnapshot,
16065            severity: GoToDiagnosticSeverityFilter,
16066            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16067        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16068            diagnostics
16069                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16070                .filter(|entry| entry.range.start != entry.range.end)
16071                .filter(|entry| !entry.diagnostic.is_unnecessary)
16072                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16073        }
16074
16075        let snapshot = self.snapshot(window, cx);
16076        let before = filtered(
16077            snapshot.clone(),
16078            severity,
16079            buffer
16080                .diagnostics_in_range(0..selection.start)
16081                .filter(|entry| entry.range.start <= selection.start),
16082        );
16083        let after = filtered(
16084            snapshot,
16085            severity,
16086            buffer
16087                .diagnostics_in_range(selection.start..buffer.len())
16088                .filter(|entry| entry.range.start >= selection.start),
16089        );
16090
16091        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16092        if direction == Direction::Prev {
16093            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16094            {
16095                for diagnostic in prev_diagnostics.into_iter().rev() {
16096                    if diagnostic.range.start != selection.start
16097                        || active_group_id
16098                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16099                    {
16100                        found = Some(diagnostic);
16101                        break 'outer;
16102                    }
16103                }
16104            }
16105        } else {
16106            for diagnostic in after.chain(before) {
16107                if diagnostic.range.start != selection.start
16108                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16109                {
16110                    found = Some(diagnostic);
16111                    break;
16112                }
16113            }
16114        }
16115        let Some(next_diagnostic) = found else {
16116            return;
16117        };
16118
16119        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16120        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16121            return;
16122        };
16123        self.change_selections(Default::default(), window, cx, |s| {
16124            s.select_ranges(vec![
16125                next_diagnostic.range.start..next_diagnostic.range.start,
16126            ])
16127        });
16128        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16129        self.refresh_edit_prediction(false, true, window, cx);
16130    }
16131
16132    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16133        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16134        let snapshot = self.snapshot(window, cx);
16135        let selection = self.selections.newest::<Point>(cx);
16136        self.go_to_hunk_before_or_after_position(
16137            &snapshot,
16138            selection.head(),
16139            Direction::Next,
16140            window,
16141            cx,
16142        );
16143    }
16144
16145    pub fn go_to_hunk_before_or_after_position(
16146        &mut self,
16147        snapshot: &EditorSnapshot,
16148        position: Point,
16149        direction: Direction,
16150        window: &mut Window,
16151        cx: &mut Context<Editor>,
16152    ) {
16153        let row = if direction == Direction::Next {
16154            self.hunk_after_position(snapshot, position)
16155                .map(|hunk| hunk.row_range.start)
16156        } else {
16157            self.hunk_before_position(snapshot, position)
16158        };
16159
16160        if let Some(row) = row {
16161            let destination = Point::new(row.0, 0);
16162            let autoscroll = Autoscroll::center();
16163
16164            self.unfold_ranges(&[destination..destination], false, false, cx);
16165            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16166                s.select_ranges([destination..destination]);
16167            });
16168        }
16169    }
16170
16171    fn hunk_after_position(
16172        &mut self,
16173        snapshot: &EditorSnapshot,
16174        position: Point,
16175    ) -> Option<MultiBufferDiffHunk> {
16176        snapshot
16177            .buffer_snapshot()
16178            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16179            .find(|hunk| hunk.row_range.start.0 > position.row)
16180            .or_else(|| {
16181                snapshot
16182                    .buffer_snapshot()
16183                    .diff_hunks_in_range(Point::zero()..position)
16184                    .find(|hunk| hunk.row_range.end.0 < position.row)
16185            })
16186    }
16187
16188    fn go_to_prev_hunk(
16189        &mut self,
16190        _: &GoToPreviousHunk,
16191        window: &mut Window,
16192        cx: &mut Context<Self>,
16193    ) {
16194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16195        let snapshot = self.snapshot(window, cx);
16196        let selection = self.selections.newest::<Point>(cx);
16197        self.go_to_hunk_before_or_after_position(
16198            &snapshot,
16199            selection.head(),
16200            Direction::Prev,
16201            window,
16202            cx,
16203        );
16204    }
16205
16206    fn hunk_before_position(
16207        &mut self,
16208        snapshot: &EditorSnapshot,
16209        position: Point,
16210    ) -> Option<MultiBufferRow> {
16211        snapshot
16212            .buffer_snapshot()
16213            .diff_hunk_before(position)
16214            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16215    }
16216
16217    fn go_to_next_change(
16218        &mut self,
16219        _: &GoToNextChange,
16220        window: &mut Window,
16221        cx: &mut Context<Self>,
16222    ) {
16223        if let Some(selections) = self
16224            .change_list
16225            .next_change(1, Direction::Next)
16226            .map(|s| s.to_vec())
16227        {
16228            self.change_selections(Default::default(), window, cx, |s| {
16229                let map = s.display_map();
16230                s.select_display_ranges(selections.iter().map(|a| {
16231                    let point = a.to_display_point(&map);
16232                    point..point
16233                }))
16234            })
16235        }
16236    }
16237
16238    fn go_to_previous_change(
16239        &mut self,
16240        _: &GoToPreviousChange,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) {
16244        if let Some(selections) = self
16245            .change_list
16246            .next_change(1, Direction::Prev)
16247            .map(|s| s.to_vec())
16248        {
16249            self.change_selections(Default::default(), window, cx, |s| {
16250                let map = s.display_map();
16251                s.select_display_ranges(selections.iter().map(|a| {
16252                    let point = a.to_display_point(&map);
16253                    point..point
16254                }))
16255            })
16256        }
16257    }
16258
16259    pub fn go_to_next_document_highlight(
16260        &mut self,
16261        _: &GoToNextDocumentHighlight,
16262        window: &mut Window,
16263        cx: &mut Context<Self>,
16264    ) {
16265        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16266    }
16267
16268    pub fn go_to_prev_document_highlight(
16269        &mut self,
16270        _: &GoToPreviousDocumentHighlight,
16271        window: &mut Window,
16272        cx: &mut Context<Self>,
16273    ) {
16274        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16275    }
16276
16277    pub fn go_to_document_highlight_before_or_after_position(
16278        &mut self,
16279        direction: Direction,
16280        window: &mut Window,
16281        cx: &mut Context<Editor>,
16282    ) {
16283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16284        let snapshot = self.snapshot(window, cx);
16285        let buffer = &snapshot.buffer_snapshot();
16286        let position = self.selections.newest::<Point>(cx).head();
16287        let anchor_position = buffer.anchor_after(position);
16288
16289        // Get all document highlights (both read and write)
16290        let mut all_highlights = Vec::new();
16291
16292        if let Some((_, read_highlights)) = self
16293            .background_highlights
16294            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16295        {
16296            all_highlights.extend(read_highlights.iter());
16297        }
16298
16299        if let Some((_, write_highlights)) = self
16300            .background_highlights
16301            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16302        {
16303            all_highlights.extend(write_highlights.iter());
16304        }
16305
16306        if all_highlights.is_empty() {
16307            return;
16308        }
16309
16310        // Sort highlights by position
16311        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16312
16313        let target_highlight = match direction {
16314            Direction::Next => {
16315                // Find the first highlight after the current position
16316                all_highlights
16317                    .iter()
16318                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16319            }
16320            Direction::Prev => {
16321                // Find the last highlight before the current position
16322                all_highlights
16323                    .iter()
16324                    .rev()
16325                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16326            }
16327        };
16328
16329        if let Some(highlight) = target_highlight {
16330            let destination = highlight.start.to_point(buffer);
16331            let autoscroll = Autoscroll::center();
16332
16333            self.unfold_ranges(&[destination..destination], false, false, cx);
16334            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16335                s.select_ranges([destination..destination]);
16336            });
16337        }
16338    }
16339
16340    fn go_to_line<T: 'static>(
16341        &mut self,
16342        position: Anchor,
16343        highlight_color: Option<Hsla>,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        let snapshot = self.snapshot(window, cx).display_snapshot;
16348        let position = position.to_point(&snapshot.buffer_snapshot());
16349        let start = snapshot
16350            .buffer_snapshot()
16351            .clip_point(Point::new(position.row, 0), Bias::Left);
16352        let end = start + Point::new(1, 0);
16353        let start = snapshot.buffer_snapshot().anchor_before(start);
16354        let end = snapshot.buffer_snapshot().anchor_before(end);
16355
16356        self.highlight_rows::<T>(
16357            start..end,
16358            highlight_color
16359                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16360            Default::default(),
16361            cx,
16362        );
16363
16364        if self.buffer.read(cx).is_singleton() {
16365            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16366        }
16367    }
16368
16369    pub fn go_to_definition(
16370        &mut self,
16371        _: &GoToDefinition,
16372        window: &mut Window,
16373        cx: &mut Context<Self>,
16374    ) -> Task<Result<Navigated>> {
16375        let definition =
16376            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16377        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16378        cx.spawn_in(window, async move |editor, cx| {
16379            if definition.await? == Navigated::Yes {
16380                return Ok(Navigated::Yes);
16381            }
16382            match fallback_strategy {
16383                GoToDefinitionFallback::None => Ok(Navigated::No),
16384                GoToDefinitionFallback::FindAllReferences => {
16385                    match editor.update_in(cx, |editor, window, cx| {
16386                        editor.find_all_references(&FindAllReferences, window, cx)
16387                    })? {
16388                        Some(references) => references.await,
16389                        None => Ok(Navigated::No),
16390                    }
16391                }
16392            }
16393        })
16394    }
16395
16396    pub fn go_to_declaration(
16397        &mut self,
16398        _: &GoToDeclaration,
16399        window: &mut Window,
16400        cx: &mut Context<Self>,
16401    ) -> Task<Result<Navigated>> {
16402        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16403    }
16404
16405    pub fn go_to_declaration_split(
16406        &mut self,
16407        _: &GoToDeclaration,
16408        window: &mut Window,
16409        cx: &mut Context<Self>,
16410    ) -> Task<Result<Navigated>> {
16411        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16412    }
16413
16414    pub fn go_to_implementation(
16415        &mut self,
16416        _: &GoToImplementation,
16417        window: &mut Window,
16418        cx: &mut Context<Self>,
16419    ) -> Task<Result<Navigated>> {
16420        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16421    }
16422
16423    pub fn go_to_implementation_split(
16424        &mut self,
16425        _: &GoToImplementationSplit,
16426        window: &mut Window,
16427        cx: &mut Context<Self>,
16428    ) -> Task<Result<Navigated>> {
16429        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16430    }
16431
16432    pub fn go_to_type_definition(
16433        &mut self,
16434        _: &GoToTypeDefinition,
16435        window: &mut Window,
16436        cx: &mut Context<Self>,
16437    ) -> Task<Result<Navigated>> {
16438        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16439    }
16440
16441    pub fn go_to_definition_split(
16442        &mut self,
16443        _: &GoToDefinitionSplit,
16444        window: &mut Window,
16445        cx: &mut Context<Self>,
16446    ) -> Task<Result<Navigated>> {
16447        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16448    }
16449
16450    pub fn go_to_type_definition_split(
16451        &mut self,
16452        _: &GoToTypeDefinitionSplit,
16453        window: &mut Window,
16454        cx: &mut Context<Self>,
16455    ) -> Task<Result<Navigated>> {
16456        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16457    }
16458
16459    fn go_to_definition_of_kind(
16460        &mut self,
16461        kind: GotoDefinitionKind,
16462        split: bool,
16463        window: &mut Window,
16464        cx: &mut Context<Self>,
16465    ) -> Task<Result<Navigated>> {
16466        let Some(provider) = self.semantics_provider.clone() else {
16467            return Task::ready(Ok(Navigated::No));
16468        };
16469        let head = self.selections.newest::<usize>(cx).head();
16470        let buffer = self.buffer.read(cx);
16471        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16472            return Task::ready(Ok(Navigated::No));
16473        };
16474        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16475            return Task::ready(Ok(Navigated::No));
16476        };
16477
16478        cx.spawn_in(window, async move |editor, cx| {
16479            let Some(definitions) = definitions.await? else {
16480                return Ok(Navigated::No);
16481            };
16482            let navigated = editor
16483                .update_in(cx, |editor, window, cx| {
16484                    editor.navigate_to_hover_links(
16485                        Some(kind),
16486                        definitions
16487                            .into_iter()
16488                            .filter(|location| {
16489                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16490                            })
16491                            .map(HoverLink::Text)
16492                            .collect::<Vec<_>>(),
16493                        split,
16494                        window,
16495                        cx,
16496                    )
16497                })?
16498                .await?;
16499            anyhow::Ok(navigated)
16500        })
16501    }
16502
16503    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16504        let selection = self.selections.newest_anchor();
16505        let head = selection.head();
16506        let tail = selection.tail();
16507
16508        let Some((buffer, start_position)) =
16509            self.buffer.read(cx).text_anchor_for_position(head, cx)
16510        else {
16511            return;
16512        };
16513
16514        let end_position = if head != tail {
16515            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16516                return;
16517            };
16518            Some(pos)
16519        } else {
16520            None
16521        };
16522
16523        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16524            let url = if let Some(end_pos) = end_position {
16525                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16526            } else {
16527                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16528            };
16529
16530            if let Some(url) = url {
16531                cx.update(|window, cx| {
16532                    if parse_zed_link(&url, cx).is_some() {
16533                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16534                    } else {
16535                        cx.open_url(&url);
16536                    }
16537                })?;
16538            }
16539
16540            anyhow::Ok(())
16541        });
16542
16543        url_finder.detach();
16544    }
16545
16546    pub fn open_selected_filename(
16547        &mut self,
16548        _: &OpenSelectedFilename,
16549        window: &mut Window,
16550        cx: &mut Context<Self>,
16551    ) {
16552        let Some(workspace) = self.workspace() else {
16553            return;
16554        };
16555
16556        let position = self.selections.newest_anchor().head();
16557
16558        let Some((buffer, buffer_position)) =
16559            self.buffer.read(cx).text_anchor_for_position(position, cx)
16560        else {
16561            return;
16562        };
16563
16564        let project = self.project.clone();
16565
16566        cx.spawn_in(window, async move |_, cx| {
16567            let result = find_file(&buffer, project, buffer_position, cx).await;
16568
16569            if let Some((_, path)) = result {
16570                workspace
16571                    .update_in(cx, |workspace, window, cx| {
16572                        workspace.open_resolved_path(path, window, cx)
16573                    })?
16574                    .await?;
16575            }
16576            anyhow::Ok(())
16577        })
16578        .detach();
16579    }
16580
16581    pub(crate) fn navigate_to_hover_links(
16582        &mut self,
16583        kind: Option<GotoDefinitionKind>,
16584        definitions: Vec<HoverLink>,
16585        split: bool,
16586        window: &mut Window,
16587        cx: &mut Context<Editor>,
16588    ) -> Task<Result<Navigated>> {
16589        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16590        let mut first_url_or_file = None;
16591        let definitions: Vec<_> = definitions
16592            .into_iter()
16593            .filter_map(|def| match def {
16594                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16595                HoverLink::InlayHint(lsp_location, server_id) => {
16596                    let computation =
16597                        self.compute_target_location(lsp_location, server_id, window, cx);
16598                    Some(cx.background_spawn(computation))
16599                }
16600                HoverLink::Url(url) => {
16601                    first_url_or_file = Some(Either::Left(url));
16602                    None
16603                }
16604                HoverLink::File(path) => {
16605                    first_url_or_file = Some(Either::Right(path));
16606                    None
16607                }
16608            })
16609            .collect();
16610
16611        let workspace = self.workspace();
16612
16613        cx.spawn_in(window, async move |editor, cx| {
16614            let locations: Vec<Location> = future::join_all(definitions)
16615                .await
16616                .into_iter()
16617                .filter_map(|location| location.transpose())
16618                .collect::<Result<_>>()
16619                .context("location tasks")?;
16620            let mut locations = cx.update(|_, cx| {
16621                locations
16622                    .into_iter()
16623                    .map(|location| {
16624                        let buffer = location.buffer.read(cx);
16625                        (location.buffer, location.range.to_point(buffer))
16626                    })
16627                    .into_group_map()
16628            })?;
16629            let mut num_locations = 0;
16630            for ranges in locations.values_mut() {
16631                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16632                ranges.dedup();
16633                num_locations += ranges.len();
16634            }
16635
16636            if num_locations > 1 {
16637                let Some(workspace) = workspace else {
16638                    return Ok(Navigated::No);
16639                };
16640
16641                let tab_kind = match kind {
16642                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16643                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16644                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16645                    Some(GotoDefinitionKind::Type) => "Types",
16646                };
16647                let title = editor
16648                    .update_in(cx, |_, _, cx| {
16649                        let target = locations
16650                            .iter()
16651                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16652                            .map(|(buffer, location)| {
16653                                buffer
16654                                    .read(cx)
16655                                    .text_for_range(location.clone())
16656                                    .collect::<String>()
16657                            })
16658                            .filter(|text| !text.contains('\n'))
16659                            .unique()
16660                            .take(3)
16661                            .join(", ");
16662                        if target.is_empty() {
16663                            tab_kind.to_owned()
16664                        } else {
16665                            format!("{tab_kind} for {target}")
16666                        }
16667                    })
16668                    .context("buffer title")?;
16669
16670                let opened = workspace
16671                    .update_in(cx, |workspace, window, cx| {
16672                        Self::open_locations_in_multibuffer(
16673                            workspace,
16674                            locations,
16675                            title,
16676                            split,
16677                            MultibufferSelectionMode::First,
16678                            window,
16679                            cx,
16680                        )
16681                    })
16682                    .is_ok();
16683
16684                anyhow::Ok(Navigated::from_bool(opened))
16685            } else if num_locations == 0 {
16686                // If there is one url or file, open it directly
16687                match first_url_or_file {
16688                    Some(Either::Left(url)) => {
16689                        cx.update(|_, cx| cx.open_url(&url))?;
16690                        Ok(Navigated::Yes)
16691                    }
16692                    Some(Either::Right(path)) => {
16693                        let Some(workspace) = workspace else {
16694                            return Ok(Navigated::No);
16695                        };
16696
16697                        workspace
16698                            .update_in(cx, |workspace, window, cx| {
16699                                workspace.open_resolved_path(path, window, cx)
16700                            })?
16701                            .await?;
16702                        Ok(Navigated::Yes)
16703                    }
16704                    None => Ok(Navigated::No),
16705                }
16706            } else {
16707                let Some(workspace) = workspace else {
16708                    return Ok(Navigated::No);
16709                };
16710
16711                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16712                let target_range = target_ranges.first().unwrap().clone();
16713
16714                editor.update_in(cx, |editor, window, cx| {
16715                    let range = target_range.to_point(target_buffer.read(cx));
16716                    let range = editor.range_for_match(&range);
16717                    let range = collapse_multiline_range(range);
16718
16719                    if !split
16720                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16721                    {
16722                        editor.go_to_singleton_buffer_range(range, window, cx);
16723                    } else {
16724                        let pane = workspace.read(cx).active_pane().clone();
16725                        window.defer(cx, move |window, cx| {
16726                            let target_editor: Entity<Self> =
16727                                workspace.update(cx, |workspace, cx| {
16728                                    let pane = if split {
16729                                        workspace.adjacent_pane(window, cx)
16730                                    } else {
16731                                        workspace.active_pane().clone()
16732                                    };
16733
16734                                    workspace.open_project_item(
16735                                        pane,
16736                                        target_buffer.clone(),
16737                                        true,
16738                                        true,
16739                                        window,
16740                                        cx,
16741                                    )
16742                                });
16743                            target_editor.update(cx, |target_editor, cx| {
16744                                // When selecting a definition in a different buffer, disable the nav history
16745                                // to avoid creating a history entry at the previous cursor location.
16746                                pane.update(cx, |pane, _| pane.disable_history());
16747                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16748                                pane.update(cx, |pane, _| pane.enable_history());
16749                            });
16750                        });
16751                    }
16752                    Navigated::Yes
16753                })
16754            }
16755        })
16756    }
16757
16758    fn compute_target_location(
16759        &self,
16760        lsp_location: lsp::Location,
16761        server_id: LanguageServerId,
16762        window: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) -> Task<anyhow::Result<Option<Location>>> {
16765        let Some(project) = self.project.clone() else {
16766            return Task::ready(Ok(None));
16767        };
16768
16769        cx.spawn_in(window, async move |editor, cx| {
16770            let location_task = editor.update(cx, |_, cx| {
16771                project.update(cx, |project, cx| {
16772                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16773                })
16774            })?;
16775            let location = Some({
16776                let target_buffer_handle = location_task.await.context("open local buffer")?;
16777                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16778                    let target_start = target_buffer
16779                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16780                    let target_end = target_buffer
16781                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16782                    target_buffer.anchor_after(target_start)
16783                        ..target_buffer.anchor_before(target_end)
16784                })?;
16785                Location {
16786                    buffer: target_buffer_handle,
16787                    range,
16788                }
16789            });
16790            Ok(location)
16791        })
16792    }
16793
16794    pub fn find_all_references(
16795        &mut self,
16796        _: &FindAllReferences,
16797        window: &mut Window,
16798        cx: &mut Context<Self>,
16799    ) -> Option<Task<Result<Navigated>>> {
16800        let selection = self.selections.newest::<usize>(cx);
16801        let multi_buffer = self.buffer.read(cx);
16802        let head = selection.head();
16803
16804        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16805        let head_anchor = multi_buffer_snapshot.anchor_at(
16806            head,
16807            if head < selection.tail() {
16808                Bias::Right
16809            } else {
16810                Bias::Left
16811            },
16812        );
16813
16814        match self
16815            .find_all_references_task_sources
16816            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16817        {
16818            Ok(_) => {
16819                log::info!(
16820                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16821                );
16822                return None;
16823            }
16824            Err(i) => {
16825                self.find_all_references_task_sources.insert(i, head_anchor);
16826            }
16827        }
16828
16829        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16830        let workspace = self.workspace()?;
16831        let project = workspace.read(cx).project().clone();
16832        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16833        Some(cx.spawn_in(window, async move |editor, cx| {
16834            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16835                if let Ok(i) = editor
16836                    .find_all_references_task_sources
16837                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16838                {
16839                    editor.find_all_references_task_sources.remove(i);
16840                }
16841            });
16842
16843            let Some(locations) = references.await? else {
16844                return anyhow::Ok(Navigated::No);
16845            };
16846            let mut locations = cx.update(|_, cx| {
16847                locations
16848                    .into_iter()
16849                    .map(|location| {
16850                        let buffer = location.buffer.read(cx);
16851                        (location.buffer, location.range.to_point(buffer))
16852                    })
16853                    .into_group_map()
16854            })?;
16855            if locations.is_empty() {
16856                return anyhow::Ok(Navigated::No);
16857            }
16858            for ranges in locations.values_mut() {
16859                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16860                ranges.dedup();
16861            }
16862
16863            workspace.update_in(cx, |workspace, window, cx| {
16864                let target = locations
16865                    .iter()
16866                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16867                    .map(|(buffer, location)| {
16868                        buffer
16869                            .read(cx)
16870                            .text_for_range(location.clone())
16871                            .collect::<String>()
16872                    })
16873                    .filter(|text| !text.contains('\n'))
16874                    .unique()
16875                    .take(3)
16876                    .join(", ");
16877                let title = if target.is_empty() {
16878                    "References".to_owned()
16879                } else {
16880                    format!("References to {target}")
16881                };
16882                Self::open_locations_in_multibuffer(
16883                    workspace,
16884                    locations,
16885                    title,
16886                    false,
16887                    MultibufferSelectionMode::First,
16888                    window,
16889                    cx,
16890                );
16891                Navigated::Yes
16892            })
16893        }))
16894    }
16895
16896    /// Opens a multibuffer with the given project locations in it
16897    pub fn open_locations_in_multibuffer(
16898        workspace: &mut Workspace,
16899        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16900        title: String,
16901        split: bool,
16902        multibuffer_selection_mode: MultibufferSelectionMode,
16903        window: &mut Window,
16904        cx: &mut Context<Workspace>,
16905    ) {
16906        if locations.is_empty() {
16907            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16908            return;
16909        }
16910
16911        let capability = workspace.project().read(cx).capability();
16912        let mut ranges = <Vec<Range<Anchor>>>::new();
16913
16914        // a key to find existing multibuffer editors with the same set of locations
16915        // to prevent us from opening more and more multibuffer tabs for searches and the like
16916        let mut key = (title.clone(), vec![]);
16917        let excerpt_buffer = cx.new(|cx| {
16918            let key = &mut key.1;
16919            let mut multibuffer = MultiBuffer::new(capability);
16920            for (buffer, mut ranges_for_buffer) in locations {
16921                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16922                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16923                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16924                    PathKey::for_buffer(&buffer, cx),
16925                    buffer.clone(),
16926                    ranges_for_buffer,
16927                    multibuffer_context_lines(cx),
16928                    cx,
16929                );
16930                ranges.extend(new_ranges)
16931            }
16932
16933            multibuffer.with_title(title)
16934        });
16935        let existing = workspace.active_pane().update(cx, |pane, cx| {
16936            pane.items()
16937                .filter_map(|item| item.downcast::<Editor>())
16938                .find(|editor| {
16939                    editor
16940                        .read(cx)
16941                        .lookup_key
16942                        .as_ref()
16943                        .and_then(|it| {
16944                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16945                        })
16946                        .is_some_and(|it| *it == key)
16947                })
16948        });
16949        let editor = existing.unwrap_or_else(|| {
16950            cx.new(|cx| {
16951                let mut editor = Editor::for_multibuffer(
16952                    excerpt_buffer,
16953                    Some(workspace.project().clone()),
16954                    window,
16955                    cx,
16956                );
16957                editor.lookup_key = Some(Box::new(key));
16958                editor
16959            })
16960        });
16961        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
16962            MultibufferSelectionMode::First => {
16963                if let Some(first_range) = ranges.first() {
16964                    editor.change_selections(
16965                        SelectionEffects::no_scroll(),
16966                        window,
16967                        cx,
16968                        |selections| {
16969                            selections.clear_disjoint();
16970                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
16971                        },
16972                    );
16973                }
16974                editor.highlight_background::<Self>(
16975                    &ranges,
16976                    |theme| theme.colors().editor_highlighted_line_background,
16977                    cx,
16978                );
16979            }
16980            MultibufferSelectionMode::All => {
16981                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16982                    selections.clear_disjoint();
16983                    selections.select_anchor_ranges(ranges);
16984                });
16985            }
16986        });
16987
16988        let item = Box::new(editor);
16989        let item_id = item.item_id();
16990
16991        if split {
16992            let pane = workspace.adjacent_pane(window, cx);
16993            workspace.add_item(pane, item, None, true, true, window, cx);
16994        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16995            let (preview_item_id, preview_item_idx) =
16996                workspace.active_pane().read_with(cx, |pane, _| {
16997                    (pane.preview_item_id(), pane.preview_item_idx())
16998                });
16999
17000            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17001
17002            if let Some(preview_item_id) = preview_item_id {
17003                workspace.active_pane().update(cx, |pane, cx| {
17004                    pane.remove_item(preview_item_id, false, false, window, cx);
17005                });
17006            }
17007        } else {
17008            workspace.add_item_to_active_pane(item, None, true, window, cx);
17009        }
17010        workspace.active_pane().update(cx, |pane, cx| {
17011            pane.set_preview_item_id(Some(item_id), cx);
17012        });
17013    }
17014
17015    pub fn rename(
17016        &mut self,
17017        _: &Rename,
17018        window: &mut Window,
17019        cx: &mut Context<Self>,
17020    ) -> Option<Task<Result<()>>> {
17021        use language::ToOffset as _;
17022
17023        let provider = self.semantics_provider.clone()?;
17024        let selection = self.selections.newest_anchor().clone();
17025        let (cursor_buffer, cursor_buffer_position) = self
17026            .buffer
17027            .read(cx)
17028            .text_anchor_for_position(selection.head(), cx)?;
17029        let (tail_buffer, cursor_buffer_position_end) = self
17030            .buffer
17031            .read(cx)
17032            .text_anchor_for_position(selection.tail(), cx)?;
17033        if tail_buffer != cursor_buffer {
17034            return None;
17035        }
17036
17037        let snapshot = cursor_buffer.read(cx).snapshot();
17038        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17039        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17040        let prepare_rename = provider
17041            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17042            .unwrap_or_else(|| Task::ready(Ok(None)));
17043        drop(snapshot);
17044
17045        Some(cx.spawn_in(window, async move |this, cx| {
17046            let rename_range = if let Some(range) = prepare_rename.await? {
17047                Some(range)
17048            } else {
17049                this.update(cx, |this, cx| {
17050                    let buffer = this.buffer.read(cx).snapshot(cx);
17051                    let mut buffer_highlights = this
17052                        .document_highlights_for_position(selection.head(), &buffer)
17053                        .filter(|highlight| {
17054                            highlight.start.excerpt_id == selection.head().excerpt_id
17055                                && highlight.end.excerpt_id == selection.head().excerpt_id
17056                        });
17057                    buffer_highlights
17058                        .next()
17059                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17060                })?
17061            };
17062            if let Some(rename_range) = rename_range {
17063                this.update_in(cx, |this, window, cx| {
17064                    let snapshot = cursor_buffer.read(cx).snapshot();
17065                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17066                    let cursor_offset_in_rename_range =
17067                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17068                    let cursor_offset_in_rename_range_end =
17069                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17070
17071                    this.take_rename(false, window, cx);
17072                    let buffer = this.buffer.read(cx).read(cx);
17073                    let cursor_offset = selection.head().to_offset(&buffer);
17074                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17075                    let rename_end = rename_start + rename_buffer_range.len();
17076                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17077                    let mut old_highlight_id = None;
17078                    let old_name: Arc<str> = buffer
17079                        .chunks(rename_start..rename_end, true)
17080                        .map(|chunk| {
17081                            if old_highlight_id.is_none() {
17082                                old_highlight_id = chunk.syntax_highlight_id;
17083                            }
17084                            chunk.text
17085                        })
17086                        .collect::<String>()
17087                        .into();
17088
17089                    drop(buffer);
17090
17091                    // Position the selection in the rename editor so that it matches the current selection.
17092                    this.show_local_selections = false;
17093                    let rename_editor = cx.new(|cx| {
17094                        let mut editor = Editor::single_line(window, cx);
17095                        editor.buffer.update(cx, |buffer, cx| {
17096                            buffer.edit([(0..0, old_name.clone())], None, cx)
17097                        });
17098                        let rename_selection_range = match cursor_offset_in_rename_range
17099                            .cmp(&cursor_offset_in_rename_range_end)
17100                        {
17101                            Ordering::Equal => {
17102                                editor.select_all(&SelectAll, window, cx);
17103                                return editor;
17104                            }
17105                            Ordering::Less => {
17106                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17107                            }
17108                            Ordering::Greater => {
17109                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17110                            }
17111                        };
17112                        if rename_selection_range.end > old_name.len() {
17113                            editor.select_all(&SelectAll, window, cx);
17114                        } else {
17115                            editor.change_selections(Default::default(), window, cx, |s| {
17116                                s.select_ranges([rename_selection_range]);
17117                            });
17118                        }
17119                        editor
17120                    });
17121                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17122                        if e == &EditorEvent::Focused {
17123                            cx.emit(EditorEvent::FocusedIn)
17124                        }
17125                    })
17126                    .detach();
17127
17128                    let write_highlights =
17129                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17130                    let read_highlights =
17131                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17132                    let ranges = write_highlights
17133                        .iter()
17134                        .flat_map(|(_, ranges)| ranges.iter())
17135                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17136                        .cloned()
17137                        .collect();
17138
17139                    this.highlight_text::<Rename>(
17140                        ranges,
17141                        HighlightStyle {
17142                            fade_out: Some(0.6),
17143                            ..Default::default()
17144                        },
17145                        cx,
17146                    );
17147                    let rename_focus_handle = rename_editor.focus_handle(cx);
17148                    window.focus(&rename_focus_handle);
17149                    let block_id = this.insert_blocks(
17150                        [BlockProperties {
17151                            style: BlockStyle::Flex,
17152                            placement: BlockPlacement::Below(range.start),
17153                            height: Some(1),
17154                            render: Arc::new({
17155                                let rename_editor = rename_editor.clone();
17156                                move |cx: &mut BlockContext| {
17157                                    let mut text_style = cx.editor_style.text.clone();
17158                                    if let Some(highlight_style) = old_highlight_id
17159                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17160                                    {
17161                                        text_style = text_style.highlight(highlight_style);
17162                                    }
17163                                    div()
17164                                        .block_mouse_except_scroll()
17165                                        .pl(cx.anchor_x)
17166                                        .child(EditorElement::new(
17167                                            &rename_editor,
17168                                            EditorStyle {
17169                                                background: cx.theme().system().transparent,
17170                                                local_player: cx.editor_style.local_player,
17171                                                text: text_style,
17172                                                scrollbar_width: cx.editor_style.scrollbar_width,
17173                                                syntax: cx.editor_style.syntax.clone(),
17174                                                status: cx.editor_style.status.clone(),
17175                                                inlay_hints_style: HighlightStyle {
17176                                                    font_weight: Some(FontWeight::BOLD),
17177                                                    ..make_inlay_hints_style(cx.app)
17178                                                },
17179                                                edit_prediction_styles: make_suggestion_styles(
17180                                                    cx.app,
17181                                                ),
17182                                                ..EditorStyle::default()
17183                                            },
17184                                        ))
17185                                        .into_any_element()
17186                                }
17187                            }),
17188                            priority: 0,
17189                        }],
17190                        Some(Autoscroll::fit()),
17191                        cx,
17192                    )[0];
17193                    this.pending_rename = Some(RenameState {
17194                        range,
17195                        old_name,
17196                        editor: rename_editor,
17197                        block_id,
17198                    });
17199                })?;
17200            }
17201
17202            Ok(())
17203        }))
17204    }
17205
17206    pub fn confirm_rename(
17207        &mut self,
17208        _: &ConfirmRename,
17209        window: &mut Window,
17210        cx: &mut Context<Self>,
17211    ) -> Option<Task<Result<()>>> {
17212        let rename = self.take_rename(false, window, cx)?;
17213        let workspace = self.workspace()?.downgrade();
17214        let (buffer, start) = self
17215            .buffer
17216            .read(cx)
17217            .text_anchor_for_position(rename.range.start, cx)?;
17218        let (end_buffer, _) = self
17219            .buffer
17220            .read(cx)
17221            .text_anchor_for_position(rename.range.end, cx)?;
17222        if buffer != end_buffer {
17223            return None;
17224        }
17225
17226        let old_name = rename.old_name;
17227        let new_name = rename.editor.read(cx).text(cx);
17228
17229        let rename = self.semantics_provider.as_ref()?.perform_rename(
17230            &buffer,
17231            start,
17232            new_name.clone(),
17233            cx,
17234        )?;
17235
17236        Some(cx.spawn_in(window, async move |editor, cx| {
17237            let project_transaction = rename.await?;
17238            Self::open_project_transaction(
17239                &editor,
17240                workspace,
17241                project_transaction,
17242                format!("Rename: {}{}", old_name, new_name),
17243                cx,
17244            )
17245            .await?;
17246
17247            editor.update(cx, |editor, cx| {
17248                editor.refresh_document_highlights(cx);
17249            })?;
17250            Ok(())
17251        }))
17252    }
17253
17254    fn take_rename(
17255        &mut self,
17256        moving_cursor: bool,
17257        window: &mut Window,
17258        cx: &mut Context<Self>,
17259    ) -> Option<RenameState> {
17260        let rename = self.pending_rename.take()?;
17261        if rename.editor.focus_handle(cx).is_focused(window) {
17262            window.focus(&self.focus_handle);
17263        }
17264
17265        self.remove_blocks(
17266            [rename.block_id].into_iter().collect(),
17267            Some(Autoscroll::fit()),
17268            cx,
17269        );
17270        self.clear_highlights::<Rename>(cx);
17271        self.show_local_selections = true;
17272
17273        if moving_cursor {
17274            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17275                editor.selections.newest::<usize>(cx).head()
17276            });
17277
17278            // Update the selection to match the position of the selection inside
17279            // the rename editor.
17280            let snapshot = self.buffer.read(cx).read(cx);
17281            let rename_range = rename.range.to_offset(&snapshot);
17282            let cursor_in_editor = snapshot
17283                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17284                .min(rename_range.end);
17285            drop(snapshot);
17286
17287            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17288                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17289            });
17290        } else {
17291            self.refresh_document_highlights(cx);
17292        }
17293
17294        Some(rename)
17295    }
17296
17297    pub fn pending_rename(&self) -> Option<&RenameState> {
17298        self.pending_rename.as_ref()
17299    }
17300
17301    fn format(
17302        &mut self,
17303        _: &Format,
17304        window: &mut Window,
17305        cx: &mut Context<Self>,
17306    ) -> Option<Task<Result<()>>> {
17307        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17308
17309        let project = match &self.project {
17310            Some(project) => project.clone(),
17311            None => return None,
17312        };
17313
17314        Some(self.perform_format(
17315            project,
17316            FormatTrigger::Manual,
17317            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17318            window,
17319            cx,
17320        ))
17321    }
17322
17323    fn format_selections(
17324        &mut self,
17325        _: &FormatSelections,
17326        window: &mut Window,
17327        cx: &mut Context<Self>,
17328    ) -> Option<Task<Result<()>>> {
17329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17330
17331        let project = match &self.project {
17332            Some(project) => project.clone(),
17333            None => return None,
17334        };
17335
17336        let ranges = self
17337            .selections
17338            .all_adjusted(cx)
17339            .into_iter()
17340            .map(|selection| selection.range())
17341            .collect_vec();
17342
17343        Some(self.perform_format(
17344            project,
17345            FormatTrigger::Manual,
17346            FormatTarget::Ranges(ranges),
17347            window,
17348            cx,
17349        ))
17350    }
17351
17352    fn perform_format(
17353        &mut self,
17354        project: Entity<Project>,
17355        trigger: FormatTrigger,
17356        target: FormatTarget,
17357        window: &mut Window,
17358        cx: &mut Context<Self>,
17359    ) -> Task<Result<()>> {
17360        let buffer = self.buffer.clone();
17361        let (buffers, target) = match target {
17362            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17363            FormatTarget::Ranges(selection_ranges) => {
17364                let multi_buffer = buffer.read(cx);
17365                let snapshot = multi_buffer.read(cx);
17366                let mut buffers = HashSet::default();
17367                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17368                    BTreeMap::new();
17369                for selection_range in selection_ranges {
17370                    for (buffer, buffer_range, _) in
17371                        snapshot.range_to_buffer_ranges(selection_range)
17372                    {
17373                        let buffer_id = buffer.remote_id();
17374                        let start = buffer.anchor_before(buffer_range.start);
17375                        let end = buffer.anchor_after(buffer_range.end);
17376                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17377                        buffer_id_to_ranges
17378                            .entry(buffer_id)
17379                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17380                            .or_insert_with(|| vec![start..end]);
17381                    }
17382                }
17383                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17384            }
17385        };
17386
17387        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17388        let selections_prev = transaction_id_prev
17389            .and_then(|transaction_id_prev| {
17390                // default to selections as they were after the last edit, if we have them,
17391                // instead of how they are now.
17392                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17393                // will take you back to where you made the last edit, instead of staying where you scrolled
17394                self.selection_history
17395                    .transaction(transaction_id_prev)
17396                    .map(|t| t.0.clone())
17397            })
17398            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17399
17400        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17401        let format = project.update(cx, |project, cx| {
17402            project.format(buffers, target, true, trigger, cx)
17403        });
17404
17405        cx.spawn_in(window, async move |editor, cx| {
17406            let transaction = futures::select_biased! {
17407                transaction = format.log_err().fuse() => transaction,
17408                () = timeout => {
17409                    log::warn!("timed out waiting for formatting");
17410                    None
17411                }
17412            };
17413
17414            buffer
17415                .update(cx, |buffer, cx| {
17416                    if let Some(transaction) = transaction
17417                        && !buffer.is_singleton()
17418                    {
17419                        buffer.push_transaction(&transaction.0, cx);
17420                    }
17421                    cx.notify();
17422                })
17423                .ok();
17424
17425            if let Some(transaction_id_now) =
17426                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17427            {
17428                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17429                if has_new_transaction {
17430                    _ = editor.update(cx, |editor, _| {
17431                        editor
17432                            .selection_history
17433                            .insert_transaction(transaction_id_now, selections_prev);
17434                    });
17435                }
17436            }
17437
17438            Ok(())
17439        })
17440    }
17441
17442    fn organize_imports(
17443        &mut self,
17444        _: &OrganizeImports,
17445        window: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) -> Option<Task<Result<()>>> {
17448        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17449        let project = match &self.project {
17450            Some(project) => project.clone(),
17451            None => return None,
17452        };
17453        Some(self.perform_code_action_kind(
17454            project,
17455            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17456            window,
17457            cx,
17458        ))
17459    }
17460
17461    fn perform_code_action_kind(
17462        &mut self,
17463        project: Entity<Project>,
17464        kind: CodeActionKind,
17465        window: &mut Window,
17466        cx: &mut Context<Self>,
17467    ) -> Task<Result<()>> {
17468        let buffer = self.buffer.clone();
17469        let buffers = buffer.read(cx).all_buffers();
17470        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17471        let apply_action = project.update(cx, |project, cx| {
17472            project.apply_code_action_kind(buffers, kind, true, cx)
17473        });
17474        cx.spawn_in(window, async move |_, cx| {
17475            let transaction = futures::select_biased! {
17476                () = timeout => {
17477                    log::warn!("timed out waiting for executing code action");
17478                    None
17479                }
17480                transaction = apply_action.log_err().fuse() => transaction,
17481            };
17482            buffer
17483                .update(cx, |buffer, cx| {
17484                    // check if we need this
17485                    if let Some(transaction) = transaction
17486                        && !buffer.is_singleton()
17487                    {
17488                        buffer.push_transaction(&transaction.0, cx);
17489                    }
17490                    cx.notify();
17491                })
17492                .ok();
17493            Ok(())
17494        })
17495    }
17496
17497    pub fn restart_language_server(
17498        &mut self,
17499        _: &RestartLanguageServer,
17500        _: &mut Window,
17501        cx: &mut Context<Self>,
17502    ) {
17503        if let Some(project) = self.project.clone() {
17504            self.buffer.update(cx, |multi_buffer, cx| {
17505                project.update(cx, |project, cx| {
17506                    project.restart_language_servers_for_buffers(
17507                        multi_buffer.all_buffers().into_iter().collect(),
17508                        HashSet::default(),
17509                        cx,
17510                    );
17511                });
17512            })
17513        }
17514    }
17515
17516    pub fn stop_language_server(
17517        &mut self,
17518        _: &StopLanguageServer,
17519        _: &mut Window,
17520        cx: &mut Context<Self>,
17521    ) {
17522        if let Some(project) = self.project.clone() {
17523            self.buffer.update(cx, |multi_buffer, cx| {
17524                project.update(cx, |project, cx| {
17525                    project.stop_language_servers_for_buffers(
17526                        multi_buffer.all_buffers().into_iter().collect(),
17527                        HashSet::default(),
17528                        cx,
17529                    );
17530                    cx.emit(project::Event::RefreshInlayHints);
17531                });
17532            });
17533        }
17534    }
17535
17536    fn cancel_language_server_work(
17537        workspace: &mut Workspace,
17538        _: &actions::CancelLanguageServerWork,
17539        _: &mut Window,
17540        cx: &mut Context<Workspace>,
17541    ) {
17542        let project = workspace.project();
17543        let buffers = workspace
17544            .active_item(cx)
17545            .and_then(|item| item.act_as::<Editor>(cx))
17546            .map_or(HashSet::default(), |editor| {
17547                editor.read(cx).buffer.read(cx).all_buffers()
17548            });
17549        project.update(cx, |project, cx| {
17550            project.cancel_language_server_work_for_buffers(buffers, cx);
17551        });
17552    }
17553
17554    fn show_character_palette(
17555        &mut self,
17556        _: &ShowCharacterPalette,
17557        window: &mut Window,
17558        _: &mut Context<Self>,
17559    ) {
17560        window.show_character_palette();
17561    }
17562
17563    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17564        if !self.diagnostics_enabled() {
17565            return;
17566        }
17567
17568        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17569            let buffer = self.buffer.read(cx).snapshot(cx);
17570            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17571            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17572            let is_valid = buffer
17573                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17574                .any(|entry| {
17575                    entry.diagnostic.is_primary
17576                        && !entry.range.is_empty()
17577                        && entry.range.start == primary_range_start
17578                        && entry.diagnostic.message == active_diagnostics.active_message
17579                });
17580
17581            if !is_valid {
17582                self.dismiss_diagnostics(cx);
17583            }
17584        }
17585    }
17586
17587    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17588        match &self.active_diagnostics {
17589            ActiveDiagnostic::Group(group) => Some(group),
17590            _ => None,
17591        }
17592    }
17593
17594    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17595        if !self.diagnostics_enabled() {
17596            return;
17597        }
17598        self.dismiss_diagnostics(cx);
17599        self.active_diagnostics = ActiveDiagnostic::All;
17600    }
17601
17602    fn activate_diagnostics(
17603        &mut self,
17604        buffer_id: BufferId,
17605        diagnostic: DiagnosticEntryRef<'_, usize>,
17606        window: &mut Window,
17607        cx: &mut Context<Self>,
17608    ) {
17609        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17610            return;
17611        }
17612        self.dismiss_diagnostics(cx);
17613        let snapshot = self.snapshot(window, cx);
17614        let buffer = self.buffer.read(cx).snapshot(cx);
17615        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17616            return;
17617        };
17618
17619        let diagnostic_group = buffer
17620            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17621            .collect::<Vec<_>>();
17622
17623        let blocks =
17624            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17625
17626        let blocks = self.display_map.update(cx, |display_map, cx| {
17627            display_map.insert_blocks(blocks, cx).into_iter().collect()
17628        });
17629        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17630            active_range: buffer.anchor_before(diagnostic.range.start)
17631                ..buffer.anchor_after(diagnostic.range.end),
17632            active_message: diagnostic.diagnostic.message.clone(),
17633            group_id: diagnostic.diagnostic.group_id,
17634            blocks,
17635        });
17636        cx.notify();
17637    }
17638
17639    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17640        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17641            return;
17642        };
17643
17644        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17645        if let ActiveDiagnostic::Group(group) = prev {
17646            self.display_map.update(cx, |display_map, cx| {
17647                display_map.remove_blocks(group.blocks, cx);
17648            });
17649            cx.notify();
17650        }
17651    }
17652
17653    /// Disable inline diagnostics rendering for this editor.
17654    pub fn disable_inline_diagnostics(&mut self) {
17655        self.inline_diagnostics_enabled = false;
17656        self.inline_diagnostics_update = Task::ready(());
17657        self.inline_diagnostics.clear();
17658    }
17659
17660    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17661        self.diagnostics_enabled = false;
17662        self.dismiss_diagnostics(cx);
17663        self.inline_diagnostics_update = Task::ready(());
17664        self.inline_diagnostics.clear();
17665    }
17666
17667    pub fn disable_word_completions(&mut self) {
17668        self.word_completions_enabled = false;
17669    }
17670
17671    pub fn diagnostics_enabled(&self) -> bool {
17672        self.diagnostics_enabled && self.mode.is_full()
17673    }
17674
17675    pub fn inline_diagnostics_enabled(&self) -> bool {
17676        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17677    }
17678
17679    pub fn show_inline_diagnostics(&self) -> bool {
17680        self.show_inline_diagnostics
17681    }
17682
17683    pub fn toggle_inline_diagnostics(
17684        &mut self,
17685        _: &ToggleInlineDiagnostics,
17686        window: &mut Window,
17687        cx: &mut Context<Editor>,
17688    ) {
17689        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17690        self.refresh_inline_diagnostics(false, window, cx);
17691    }
17692
17693    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17694        self.diagnostics_max_severity = severity;
17695        self.display_map.update(cx, |display_map, _| {
17696            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17697        });
17698    }
17699
17700    pub fn toggle_diagnostics(
17701        &mut self,
17702        _: &ToggleDiagnostics,
17703        window: &mut Window,
17704        cx: &mut Context<Editor>,
17705    ) {
17706        if !self.diagnostics_enabled() {
17707            return;
17708        }
17709
17710        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17711            EditorSettings::get_global(cx)
17712                .diagnostics_max_severity
17713                .filter(|severity| severity != &DiagnosticSeverity::Off)
17714                .unwrap_or(DiagnosticSeverity::Hint)
17715        } else {
17716            DiagnosticSeverity::Off
17717        };
17718        self.set_max_diagnostics_severity(new_severity, cx);
17719        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17720            self.active_diagnostics = ActiveDiagnostic::None;
17721            self.inline_diagnostics_update = Task::ready(());
17722            self.inline_diagnostics.clear();
17723        } else {
17724            self.refresh_inline_diagnostics(false, window, cx);
17725        }
17726
17727        cx.notify();
17728    }
17729
17730    pub fn toggle_minimap(
17731        &mut self,
17732        _: &ToggleMinimap,
17733        window: &mut Window,
17734        cx: &mut Context<Editor>,
17735    ) {
17736        if self.supports_minimap(cx) {
17737            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17738        }
17739    }
17740
17741    fn refresh_inline_diagnostics(
17742        &mut self,
17743        debounce: bool,
17744        window: &mut Window,
17745        cx: &mut Context<Self>,
17746    ) {
17747        let max_severity = ProjectSettings::get_global(cx)
17748            .diagnostics
17749            .inline
17750            .max_severity
17751            .unwrap_or(self.diagnostics_max_severity);
17752
17753        if !self.inline_diagnostics_enabled()
17754            || !self.show_inline_diagnostics
17755            || max_severity == DiagnosticSeverity::Off
17756        {
17757            self.inline_diagnostics_update = Task::ready(());
17758            self.inline_diagnostics.clear();
17759            return;
17760        }
17761
17762        let debounce_ms = ProjectSettings::get_global(cx)
17763            .diagnostics
17764            .inline
17765            .update_debounce_ms;
17766        let debounce = if debounce && debounce_ms > 0 {
17767            Some(Duration::from_millis(debounce_ms))
17768        } else {
17769            None
17770        };
17771        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17772            if let Some(debounce) = debounce {
17773                cx.background_executor().timer(debounce).await;
17774            }
17775            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17776                editor
17777                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17778                    .ok()
17779            }) else {
17780                return;
17781            };
17782
17783            let new_inline_diagnostics = cx
17784                .background_spawn(async move {
17785                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17786                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17787                        let message = diagnostic_entry
17788                            .diagnostic
17789                            .message
17790                            .split_once('\n')
17791                            .map(|(line, _)| line)
17792                            .map(SharedString::new)
17793                            .unwrap_or_else(|| {
17794                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17795                            });
17796                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17797                        let (Ok(i) | Err(i)) = inline_diagnostics
17798                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17799                        inline_diagnostics.insert(
17800                            i,
17801                            (
17802                                start_anchor,
17803                                InlineDiagnostic {
17804                                    message,
17805                                    group_id: diagnostic_entry.diagnostic.group_id,
17806                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17807                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17808                                    severity: diagnostic_entry.diagnostic.severity,
17809                                },
17810                            ),
17811                        );
17812                    }
17813                    inline_diagnostics
17814                })
17815                .await;
17816
17817            editor
17818                .update(cx, |editor, cx| {
17819                    editor.inline_diagnostics = new_inline_diagnostics;
17820                    cx.notify();
17821                })
17822                .ok();
17823        });
17824    }
17825
17826    fn pull_diagnostics(
17827        &mut self,
17828        buffer_id: Option<BufferId>,
17829        window: &Window,
17830        cx: &mut Context<Self>,
17831    ) -> Option<()> {
17832        if self.ignore_lsp_data() {
17833            return None;
17834        }
17835        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17836            .diagnostics
17837            .lsp_pull_diagnostics;
17838        if !pull_diagnostics_settings.enabled {
17839            return None;
17840        }
17841        let project = self.project()?.downgrade();
17842        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17843        let mut buffers = self.buffer.read(cx).all_buffers();
17844        buffers.retain(|buffer| {
17845            let buffer_id_to_retain = buffer.read(cx).remote_id();
17846            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17847                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17848        });
17849        if buffers.is_empty() {
17850            self.pull_diagnostics_task = Task::ready(());
17851            return None;
17852        }
17853
17854        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17855            cx.background_executor().timer(debounce).await;
17856
17857            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17858                buffers
17859                    .into_iter()
17860                    .filter_map(|buffer| {
17861                        project
17862                            .update(cx, |project, cx| {
17863                                project.lsp_store().update(cx, |lsp_store, cx| {
17864                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17865                                })
17866                            })
17867                            .ok()
17868                    })
17869                    .collect::<FuturesUnordered<_>>()
17870            }) else {
17871                return;
17872            };
17873
17874            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17875                match pull_task {
17876                    Ok(()) => {
17877                        if editor
17878                            .update_in(cx, |editor, window, cx| {
17879                                editor.update_diagnostics_state(window, cx);
17880                            })
17881                            .is_err()
17882                        {
17883                            return;
17884                        }
17885                    }
17886                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17887                }
17888            }
17889        });
17890
17891        Some(())
17892    }
17893
17894    pub fn set_selections_from_remote(
17895        &mut self,
17896        selections: Vec<Selection<Anchor>>,
17897        pending_selection: Option<Selection<Anchor>>,
17898        window: &mut Window,
17899        cx: &mut Context<Self>,
17900    ) {
17901        let old_cursor_position = self.selections.newest_anchor().head();
17902        self.selections.change_with(cx, |s| {
17903            s.select_anchors(selections);
17904            if let Some(pending_selection) = pending_selection {
17905                s.set_pending(pending_selection, SelectMode::Character);
17906            } else {
17907                s.clear_pending();
17908            }
17909        });
17910        self.selections_did_change(
17911            false,
17912            &old_cursor_position,
17913            SelectionEffects::default(),
17914            window,
17915            cx,
17916        );
17917    }
17918
17919    pub fn transact(
17920        &mut self,
17921        window: &mut Window,
17922        cx: &mut Context<Self>,
17923        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17924    ) -> Option<TransactionId> {
17925        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17926            this.start_transaction_at(Instant::now(), window, cx);
17927            update(this, window, cx);
17928            this.end_transaction_at(Instant::now(), cx)
17929        })
17930    }
17931
17932    pub fn start_transaction_at(
17933        &mut self,
17934        now: Instant,
17935        window: &mut Window,
17936        cx: &mut Context<Self>,
17937    ) -> Option<TransactionId> {
17938        self.end_selection(window, cx);
17939        if let Some(tx_id) = self
17940            .buffer
17941            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17942        {
17943            self.selection_history
17944                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17945            cx.emit(EditorEvent::TransactionBegun {
17946                transaction_id: tx_id,
17947            });
17948            Some(tx_id)
17949        } else {
17950            None
17951        }
17952    }
17953
17954    pub fn end_transaction_at(
17955        &mut self,
17956        now: Instant,
17957        cx: &mut Context<Self>,
17958    ) -> Option<TransactionId> {
17959        if let Some(transaction_id) = self
17960            .buffer
17961            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17962        {
17963            if let Some((_, end_selections)) =
17964                self.selection_history.transaction_mut(transaction_id)
17965            {
17966                *end_selections = Some(self.selections.disjoint_anchors_arc());
17967            } else {
17968                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17969            }
17970
17971            cx.emit(EditorEvent::Edited { transaction_id });
17972            Some(transaction_id)
17973        } else {
17974            None
17975        }
17976    }
17977
17978    pub fn modify_transaction_selection_history(
17979        &mut self,
17980        transaction_id: TransactionId,
17981        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17982    ) -> bool {
17983        self.selection_history
17984            .transaction_mut(transaction_id)
17985            .map(modify)
17986            .is_some()
17987    }
17988
17989    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17990        if self.selection_mark_mode {
17991            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17992                s.move_with(|_, sel| {
17993                    sel.collapse_to(sel.head(), SelectionGoal::None);
17994                });
17995            })
17996        }
17997        self.selection_mark_mode = true;
17998        cx.notify();
17999    }
18000
18001    pub fn swap_selection_ends(
18002        &mut self,
18003        _: &actions::SwapSelectionEnds,
18004        window: &mut Window,
18005        cx: &mut Context<Self>,
18006    ) {
18007        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18008            s.move_with(|_, sel| {
18009                if sel.start != sel.end {
18010                    sel.reversed = !sel.reversed
18011                }
18012            });
18013        });
18014        self.request_autoscroll(Autoscroll::newest(), cx);
18015        cx.notify();
18016    }
18017
18018    pub fn toggle_focus(
18019        workspace: &mut Workspace,
18020        _: &actions::ToggleFocus,
18021        window: &mut Window,
18022        cx: &mut Context<Workspace>,
18023    ) {
18024        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18025            return;
18026        };
18027        workspace.activate_item(&item, true, true, window, cx);
18028    }
18029
18030    pub fn toggle_fold(
18031        &mut self,
18032        _: &actions::ToggleFold,
18033        window: &mut Window,
18034        cx: &mut Context<Self>,
18035    ) {
18036        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18037            let selection = self.selections.newest::<Point>(cx);
18038
18039            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18040            let range = if selection.is_empty() {
18041                let point = selection.head().to_display_point(&display_map);
18042                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18043                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18044                    .to_point(&display_map);
18045                start..end
18046            } else {
18047                selection.range()
18048            };
18049            if display_map.folds_in_range(range).next().is_some() {
18050                self.unfold_lines(&Default::default(), window, cx)
18051            } else {
18052                self.fold(&Default::default(), window, cx)
18053            }
18054        } else {
18055            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18056            let buffer_ids: HashSet<_> = self
18057                .selections
18058                .disjoint_anchor_ranges()
18059                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18060                .collect();
18061
18062            let should_unfold = buffer_ids
18063                .iter()
18064                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18065
18066            for buffer_id in buffer_ids {
18067                if should_unfold {
18068                    self.unfold_buffer(buffer_id, cx);
18069                } else {
18070                    self.fold_buffer(buffer_id, cx);
18071                }
18072            }
18073        }
18074    }
18075
18076    pub fn toggle_fold_recursive(
18077        &mut self,
18078        _: &actions::ToggleFoldRecursive,
18079        window: &mut Window,
18080        cx: &mut Context<Self>,
18081    ) {
18082        let selection = self.selections.newest::<Point>(cx);
18083
18084        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18085        let range = if selection.is_empty() {
18086            let point = selection.head().to_display_point(&display_map);
18087            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18088            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18089                .to_point(&display_map);
18090            start..end
18091        } else {
18092            selection.range()
18093        };
18094        if display_map.folds_in_range(range).next().is_some() {
18095            self.unfold_recursive(&Default::default(), window, cx)
18096        } else {
18097            self.fold_recursive(&Default::default(), window, cx)
18098        }
18099    }
18100
18101    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18102        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18103            let mut to_fold = Vec::new();
18104            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18105            let selections = self.selections.all_adjusted(cx);
18106
18107            for selection in selections {
18108                let range = selection.range().sorted();
18109                let buffer_start_row = range.start.row;
18110
18111                if range.start.row != range.end.row {
18112                    let mut found = false;
18113                    let mut row = range.start.row;
18114                    while row <= range.end.row {
18115                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18116                        {
18117                            found = true;
18118                            row = crease.range().end.row + 1;
18119                            to_fold.push(crease);
18120                        } else {
18121                            row += 1
18122                        }
18123                    }
18124                    if found {
18125                        continue;
18126                    }
18127                }
18128
18129                for row in (0..=range.start.row).rev() {
18130                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18131                        && crease.range().end.row >= buffer_start_row
18132                    {
18133                        to_fold.push(crease);
18134                        if row <= range.start.row {
18135                            break;
18136                        }
18137                    }
18138                }
18139            }
18140
18141            self.fold_creases(to_fold, true, window, cx);
18142        } else {
18143            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18144            let buffer_ids = self
18145                .selections
18146                .disjoint_anchor_ranges()
18147                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18148                .collect::<HashSet<_>>();
18149            for buffer_id in buffer_ids {
18150                self.fold_buffer(buffer_id, cx);
18151            }
18152        }
18153    }
18154
18155    pub fn toggle_fold_all(
18156        &mut self,
18157        _: &actions::ToggleFoldAll,
18158        window: &mut Window,
18159        cx: &mut Context<Self>,
18160    ) {
18161        if self.buffer.read(cx).is_singleton() {
18162            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18163            let has_folds = display_map
18164                .folds_in_range(0..display_map.buffer_snapshot().len())
18165                .next()
18166                .is_some();
18167
18168            if has_folds {
18169                self.unfold_all(&actions::UnfoldAll, window, cx);
18170            } else {
18171                self.fold_all(&actions::FoldAll, window, cx);
18172            }
18173        } else {
18174            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18175            let should_unfold = buffer_ids
18176                .iter()
18177                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18178
18179            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18180                editor
18181                    .update_in(cx, |editor, _, cx| {
18182                        for buffer_id in buffer_ids {
18183                            if should_unfold {
18184                                editor.unfold_buffer(buffer_id, cx);
18185                            } else {
18186                                editor.fold_buffer(buffer_id, cx);
18187                            }
18188                        }
18189                    })
18190                    .ok();
18191            });
18192        }
18193    }
18194
18195    fn fold_at_level(
18196        &mut self,
18197        fold_at: &FoldAtLevel,
18198        window: &mut Window,
18199        cx: &mut Context<Self>,
18200    ) {
18201        if !self.buffer.read(cx).is_singleton() {
18202            return;
18203        }
18204
18205        let fold_at_level = fold_at.0;
18206        let snapshot = self.buffer.read(cx).snapshot(cx);
18207        let mut to_fold = Vec::new();
18208        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18209
18210        let row_ranges_to_keep: Vec<Range<u32>> = self
18211            .selections
18212            .all::<Point>(cx)
18213            .into_iter()
18214            .map(|sel| sel.start.row..sel.end.row)
18215            .collect();
18216
18217        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18218            while start_row < end_row {
18219                match self
18220                    .snapshot(window, cx)
18221                    .crease_for_buffer_row(MultiBufferRow(start_row))
18222                {
18223                    Some(crease) => {
18224                        let nested_start_row = crease.range().start.row + 1;
18225                        let nested_end_row = crease.range().end.row;
18226
18227                        if current_level < fold_at_level {
18228                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18229                        } else if current_level == fold_at_level {
18230                            // Fold iff there is no selection completely contained within the fold region
18231                            if !row_ranges_to_keep.iter().any(|selection| {
18232                                selection.end >= nested_start_row
18233                                    && selection.start <= nested_end_row
18234                            }) {
18235                                to_fold.push(crease);
18236                            }
18237                        }
18238
18239                        start_row = nested_end_row + 1;
18240                    }
18241                    None => start_row += 1,
18242                }
18243            }
18244        }
18245
18246        self.fold_creases(to_fold, true, window, cx);
18247    }
18248
18249    pub fn fold_at_level_1(
18250        &mut self,
18251        _: &actions::FoldAtLevel1,
18252        window: &mut Window,
18253        cx: &mut Context<Self>,
18254    ) {
18255        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18256    }
18257
18258    pub fn fold_at_level_2(
18259        &mut self,
18260        _: &actions::FoldAtLevel2,
18261        window: &mut Window,
18262        cx: &mut Context<Self>,
18263    ) {
18264        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18265    }
18266
18267    pub fn fold_at_level_3(
18268        &mut self,
18269        _: &actions::FoldAtLevel3,
18270        window: &mut Window,
18271        cx: &mut Context<Self>,
18272    ) {
18273        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18274    }
18275
18276    pub fn fold_at_level_4(
18277        &mut self,
18278        _: &actions::FoldAtLevel4,
18279        window: &mut Window,
18280        cx: &mut Context<Self>,
18281    ) {
18282        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18283    }
18284
18285    pub fn fold_at_level_5(
18286        &mut self,
18287        _: &actions::FoldAtLevel5,
18288        window: &mut Window,
18289        cx: &mut Context<Self>,
18290    ) {
18291        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18292    }
18293
18294    pub fn fold_at_level_6(
18295        &mut self,
18296        _: &actions::FoldAtLevel6,
18297        window: &mut Window,
18298        cx: &mut Context<Self>,
18299    ) {
18300        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18301    }
18302
18303    pub fn fold_at_level_7(
18304        &mut self,
18305        _: &actions::FoldAtLevel7,
18306        window: &mut Window,
18307        cx: &mut Context<Self>,
18308    ) {
18309        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18310    }
18311
18312    pub fn fold_at_level_8(
18313        &mut self,
18314        _: &actions::FoldAtLevel8,
18315        window: &mut Window,
18316        cx: &mut Context<Self>,
18317    ) {
18318        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18319    }
18320
18321    pub fn fold_at_level_9(
18322        &mut self,
18323        _: &actions::FoldAtLevel9,
18324        window: &mut Window,
18325        cx: &mut Context<Self>,
18326    ) {
18327        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18328    }
18329
18330    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18331        if self.buffer.read(cx).is_singleton() {
18332            let mut fold_ranges = Vec::new();
18333            let snapshot = self.buffer.read(cx).snapshot(cx);
18334
18335            for row in 0..snapshot.max_row().0 {
18336                if let Some(foldable_range) = self
18337                    .snapshot(window, cx)
18338                    .crease_for_buffer_row(MultiBufferRow(row))
18339                {
18340                    fold_ranges.push(foldable_range);
18341                }
18342            }
18343
18344            self.fold_creases(fold_ranges, true, window, cx);
18345        } else {
18346            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18347                editor
18348                    .update_in(cx, |editor, _, cx| {
18349                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18350                            editor.fold_buffer(buffer_id, cx);
18351                        }
18352                    })
18353                    .ok();
18354            });
18355        }
18356    }
18357
18358    pub fn fold_function_bodies(
18359        &mut self,
18360        _: &actions::FoldFunctionBodies,
18361        window: &mut Window,
18362        cx: &mut Context<Self>,
18363    ) {
18364        let snapshot = self.buffer.read(cx).snapshot(cx);
18365
18366        let ranges = snapshot
18367            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18368            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18369            .collect::<Vec<_>>();
18370
18371        let creases = ranges
18372            .into_iter()
18373            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18374            .collect();
18375
18376        self.fold_creases(creases, true, window, cx);
18377    }
18378
18379    pub fn fold_recursive(
18380        &mut self,
18381        _: &actions::FoldRecursive,
18382        window: &mut Window,
18383        cx: &mut Context<Self>,
18384    ) {
18385        let mut to_fold = Vec::new();
18386        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18387        let selections = self.selections.all_adjusted(cx);
18388
18389        for selection in selections {
18390            let range = selection.range().sorted();
18391            let buffer_start_row = range.start.row;
18392
18393            if range.start.row != range.end.row {
18394                let mut found = false;
18395                for row in range.start.row..=range.end.row {
18396                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18397                        found = true;
18398                        to_fold.push(crease);
18399                    }
18400                }
18401                if found {
18402                    continue;
18403                }
18404            }
18405
18406            for row in (0..=range.start.row).rev() {
18407                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18408                    if crease.range().end.row >= buffer_start_row {
18409                        to_fold.push(crease);
18410                    } else {
18411                        break;
18412                    }
18413                }
18414            }
18415        }
18416
18417        self.fold_creases(to_fold, true, window, cx);
18418    }
18419
18420    pub fn fold_at(
18421        &mut self,
18422        buffer_row: MultiBufferRow,
18423        window: &mut Window,
18424        cx: &mut Context<Self>,
18425    ) {
18426        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18427
18428        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18429            let autoscroll = self
18430                .selections
18431                .all::<Point>(cx)
18432                .iter()
18433                .any(|selection| crease.range().overlaps(&selection.range()));
18434
18435            self.fold_creases(vec![crease], autoscroll, window, cx);
18436        }
18437    }
18438
18439    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18440        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18441            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18442            let buffer = display_map.buffer_snapshot();
18443            let selections = self.selections.all::<Point>(cx);
18444            let ranges = selections
18445                .iter()
18446                .map(|s| {
18447                    let range = s.display_range(&display_map).sorted();
18448                    let mut start = range.start.to_point(&display_map);
18449                    let mut end = range.end.to_point(&display_map);
18450                    start.column = 0;
18451                    end.column = buffer.line_len(MultiBufferRow(end.row));
18452                    start..end
18453                })
18454                .collect::<Vec<_>>();
18455
18456            self.unfold_ranges(&ranges, true, true, cx);
18457        } else {
18458            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18459            let buffer_ids = self
18460                .selections
18461                .disjoint_anchor_ranges()
18462                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18463                .collect::<HashSet<_>>();
18464            for buffer_id in buffer_ids {
18465                self.unfold_buffer(buffer_id, cx);
18466            }
18467        }
18468    }
18469
18470    pub fn unfold_recursive(
18471        &mut self,
18472        _: &UnfoldRecursive,
18473        _window: &mut Window,
18474        cx: &mut Context<Self>,
18475    ) {
18476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18477        let selections = self.selections.all::<Point>(cx);
18478        let ranges = selections
18479            .iter()
18480            .map(|s| {
18481                let mut range = s.display_range(&display_map).sorted();
18482                *range.start.column_mut() = 0;
18483                *range.end.column_mut() = display_map.line_len(range.end.row());
18484                let start = range.start.to_point(&display_map);
18485                let end = range.end.to_point(&display_map);
18486                start..end
18487            })
18488            .collect::<Vec<_>>();
18489
18490        self.unfold_ranges(&ranges, true, true, cx);
18491    }
18492
18493    pub fn unfold_at(
18494        &mut self,
18495        buffer_row: MultiBufferRow,
18496        _window: &mut Window,
18497        cx: &mut Context<Self>,
18498    ) {
18499        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18500
18501        let intersection_range = Point::new(buffer_row.0, 0)
18502            ..Point::new(
18503                buffer_row.0,
18504                display_map.buffer_snapshot().line_len(buffer_row),
18505            );
18506
18507        let autoscroll = self
18508            .selections
18509            .all::<Point>(cx)
18510            .iter()
18511            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18512
18513        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18514    }
18515
18516    pub fn unfold_all(
18517        &mut self,
18518        _: &actions::UnfoldAll,
18519        _window: &mut Window,
18520        cx: &mut Context<Self>,
18521    ) {
18522        if self.buffer.read(cx).is_singleton() {
18523            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18524            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18525        } else {
18526            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18527                editor
18528                    .update(cx, |editor, cx| {
18529                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18530                            editor.unfold_buffer(buffer_id, cx);
18531                        }
18532                    })
18533                    .ok();
18534            });
18535        }
18536    }
18537
18538    pub fn fold_selected_ranges(
18539        &mut self,
18540        _: &FoldSelectedRanges,
18541        window: &mut Window,
18542        cx: &mut Context<Self>,
18543    ) {
18544        let selections = self.selections.all_adjusted(cx);
18545        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18546        let ranges = selections
18547            .into_iter()
18548            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18549            .collect::<Vec<_>>();
18550        self.fold_creases(ranges, true, window, cx);
18551    }
18552
18553    pub fn fold_ranges<T: ToOffset + Clone>(
18554        &mut self,
18555        ranges: Vec<Range<T>>,
18556        auto_scroll: bool,
18557        window: &mut Window,
18558        cx: &mut Context<Self>,
18559    ) {
18560        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18561        let ranges = ranges
18562            .into_iter()
18563            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18564            .collect::<Vec<_>>();
18565        self.fold_creases(ranges, auto_scroll, window, cx);
18566    }
18567
18568    pub fn fold_creases<T: ToOffset + Clone>(
18569        &mut self,
18570        creases: Vec<Crease<T>>,
18571        auto_scroll: bool,
18572        _window: &mut Window,
18573        cx: &mut Context<Self>,
18574    ) {
18575        if creases.is_empty() {
18576            return;
18577        }
18578
18579        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18580
18581        if auto_scroll {
18582            self.request_autoscroll(Autoscroll::fit(), cx);
18583        }
18584
18585        cx.notify();
18586
18587        self.scrollbar_marker_state.dirty = true;
18588        self.folds_did_change(cx);
18589    }
18590
18591    /// Removes any folds whose ranges intersect any of the given ranges.
18592    pub fn unfold_ranges<T: ToOffset + Clone>(
18593        &mut self,
18594        ranges: &[Range<T>],
18595        inclusive: bool,
18596        auto_scroll: bool,
18597        cx: &mut Context<Self>,
18598    ) {
18599        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18600            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18601        });
18602        self.folds_did_change(cx);
18603    }
18604
18605    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18606        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18607            return;
18608        }
18609        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18610        self.display_map.update(cx, |display_map, cx| {
18611            display_map.fold_buffers([buffer_id], cx)
18612        });
18613        cx.emit(EditorEvent::BufferFoldToggled {
18614            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18615            folded: true,
18616        });
18617        cx.notify();
18618    }
18619
18620    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18621        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18622            return;
18623        }
18624        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18625        self.display_map.update(cx, |display_map, cx| {
18626            display_map.unfold_buffers([buffer_id], cx);
18627        });
18628        cx.emit(EditorEvent::BufferFoldToggled {
18629            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18630            folded: false,
18631        });
18632        cx.notify();
18633    }
18634
18635    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18636        self.display_map.read(cx).is_buffer_folded(buffer)
18637    }
18638
18639    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18640        self.display_map.read(cx).folded_buffers()
18641    }
18642
18643    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18644        self.display_map.update(cx, |display_map, cx| {
18645            display_map.disable_header_for_buffer(buffer_id, cx);
18646        });
18647        cx.notify();
18648    }
18649
18650    /// Removes any folds with the given ranges.
18651    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18652        &mut self,
18653        ranges: &[Range<T>],
18654        type_id: TypeId,
18655        auto_scroll: bool,
18656        cx: &mut Context<Self>,
18657    ) {
18658        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18659            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18660        });
18661        self.folds_did_change(cx);
18662    }
18663
18664    fn remove_folds_with<T: ToOffset + Clone>(
18665        &mut self,
18666        ranges: &[Range<T>],
18667        auto_scroll: bool,
18668        cx: &mut Context<Self>,
18669        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18670    ) {
18671        if ranges.is_empty() {
18672            return;
18673        }
18674
18675        let mut buffers_affected = HashSet::default();
18676        let multi_buffer = self.buffer().read(cx);
18677        for range in ranges {
18678            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18679                buffers_affected.insert(buffer.read(cx).remote_id());
18680            };
18681        }
18682
18683        self.display_map.update(cx, update);
18684
18685        if auto_scroll {
18686            self.request_autoscroll(Autoscroll::fit(), cx);
18687        }
18688
18689        cx.notify();
18690        self.scrollbar_marker_state.dirty = true;
18691        self.active_indent_guides_state.dirty = true;
18692    }
18693
18694    pub fn update_renderer_widths(
18695        &mut self,
18696        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18697        cx: &mut Context<Self>,
18698    ) -> bool {
18699        self.display_map
18700            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18701    }
18702
18703    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18704        self.display_map.read(cx).fold_placeholder.clone()
18705    }
18706
18707    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18708        self.buffer.update(cx, |buffer, cx| {
18709            buffer.set_all_diff_hunks_expanded(cx);
18710        });
18711    }
18712
18713    pub fn expand_all_diff_hunks(
18714        &mut self,
18715        _: &ExpandAllDiffHunks,
18716        _window: &mut Window,
18717        cx: &mut Context<Self>,
18718    ) {
18719        self.buffer.update(cx, |buffer, cx| {
18720            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18721        });
18722    }
18723
18724    pub fn toggle_selected_diff_hunks(
18725        &mut self,
18726        _: &ToggleSelectedDiffHunks,
18727        _window: &mut Window,
18728        cx: &mut Context<Self>,
18729    ) {
18730        let ranges: Vec<_> = self
18731            .selections
18732            .disjoint_anchors()
18733            .iter()
18734            .map(|s| s.range())
18735            .collect();
18736        self.toggle_diff_hunks_in_ranges(ranges, cx);
18737    }
18738
18739    pub fn diff_hunks_in_ranges<'a>(
18740        &'a self,
18741        ranges: &'a [Range<Anchor>],
18742        buffer: &'a MultiBufferSnapshot,
18743    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18744        ranges.iter().flat_map(move |range| {
18745            let end_excerpt_id = range.end.excerpt_id;
18746            let range = range.to_point(buffer);
18747            let mut peek_end = range.end;
18748            if range.end.row < buffer.max_row().0 {
18749                peek_end = Point::new(range.end.row + 1, 0);
18750            }
18751            buffer
18752                .diff_hunks_in_range(range.start..peek_end)
18753                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18754        })
18755    }
18756
18757    pub fn has_stageable_diff_hunks_in_ranges(
18758        &self,
18759        ranges: &[Range<Anchor>],
18760        snapshot: &MultiBufferSnapshot,
18761    ) -> bool {
18762        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18763        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18764    }
18765
18766    pub fn toggle_staged_selected_diff_hunks(
18767        &mut self,
18768        _: &::git::ToggleStaged,
18769        _: &mut Window,
18770        cx: &mut Context<Self>,
18771    ) {
18772        let snapshot = self.buffer.read(cx).snapshot(cx);
18773        let ranges: Vec<_> = self
18774            .selections
18775            .disjoint_anchors()
18776            .iter()
18777            .map(|s| s.range())
18778            .collect();
18779        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18780        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18781    }
18782
18783    pub fn set_render_diff_hunk_controls(
18784        &mut self,
18785        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18786        cx: &mut Context<Self>,
18787    ) {
18788        self.render_diff_hunk_controls = render_diff_hunk_controls;
18789        cx.notify();
18790    }
18791
18792    pub fn stage_and_next(
18793        &mut self,
18794        _: &::git::StageAndNext,
18795        window: &mut Window,
18796        cx: &mut Context<Self>,
18797    ) {
18798        self.do_stage_or_unstage_and_next(true, window, cx);
18799    }
18800
18801    pub fn unstage_and_next(
18802        &mut self,
18803        _: &::git::UnstageAndNext,
18804        window: &mut Window,
18805        cx: &mut Context<Self>,
18806    ) {
18807        self.do_stage_or_unstage_and_next(false, window, cx);
18808    }
18809
18810    pub fn stage_or_unstage_diff_hunks(
18811        &mut self,
18812        stage: bool,
18813        ranges: Vec<Range<Anchor>>,
18814        cx: &mut Context<Self>,
18815    ) {
18816        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18817        cx.spawn(async move |this, cx| {
18818            task.await?;
18819            this.update(cx, |this, cx| {
18820                let snapshot = this.buffer.read(cx).snapshot(cx);
18821                let chunk_by = this
18822                    .diff_hunks_in_ranges(&ranges, &snapshot)
18823                    .chunk_by(|hunk| hunk.buffer_id);
18824                for (buffer_id, hunks) in &chunk_by {
18825                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18826                }
18827            })
18828        })
18829        .detach_and_log_err(cx);
18830    }
18831
18832    fn save_buffers_for_ranges_if_needed(
18833        &mut self,
18834        ranges: &[Range<Anchor>],
18835        cx: &mut Context<Editor>,
18836    ) -> Task<Result<()>> {
18837        let multibuffer = self.buffer.read(cx);
18838        let snapshot = multibuffer.read(cx);
18839        let buffer_ids: HashSet<_> = ranges
18840            .iter()
18841            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18842            .collect();
18843        drop(snapshot);
18844
18845        let mut buffers = HashSet::default();
18846        for buffer_id in buffer_ids {
18847            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18848                let buffer = buffer_entity.read(cx);
18849                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18850                {
18851                    buffers.insert(buffer_entity);
18852                }
18853            }
18854        }
18855
18856        if let Some(project) = &self.project {
18857            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18858        } else {
18859            Task::ready(Ok(()))
18860        }
18861    }
18862
18863    fn do_stage_or_unstage_and_next(
18864        &mut self,
18865        stage: bool,
18866        window: &mut Window,
18867        cx: &mut Context<Self>,
18868    ) {
18869        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18870
18871        if ranges.iter().any(|range| range.start != range.end) {
18872            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18873            return;
18874        }
18875
18876        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18877        let snapshot = self.snapshot(window, cx);
18878        let position = self.selections.newest::<Point>(cx).head();
18879        let mut row = snapshot
18880            .buffer_snapshot()
18881            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18882            .find(|hunk| hunk.row_range.start.0 > position.row)
18883            .map(|hunk| hunk.row_range.start);
18884
18885        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18886        // Outside of the project diff editor, wrap around to the beginning.
18887        if !all_diff_hunks_expanded {
18888            row = row.or_else(|| {
18889                snapshot
18890                    .buffer_snapshot()
18891                    .diff_hunks_in_range(Point::zero()..position)
18892                    .find(|hunk| hunk.row_range.end.0 < position.row)
18893                    .map(|hunk| hunk.row_range.start)
18894            });
18895        }
18896
18897        if let Some(row) = row {
18898            let destination = Point::new(row.0, 0);
18899            let autoscroll = Autoscroll::center();
18900
18901            self.unfold_ranges(&[destination..destination], false, false, cx);
18902            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18903                s.select_ranges([destination..destination]);
18904            });
18905        }
18906    }
18907
18908    fn do_stage_or_unstage(
18909        &self,
18910        stage: bool,
18911        buffer_id: BufferId,
18912        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18913        cx: &mut App,
18914    ) -> Option<()> {
18915        let project = self.project()?;
18916        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18917        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18918        let buffer_snapshot = buffer.read(cx).snapshot();
18919        let file_exists = buffer_snapshot
18920            .file()
18921            .is_some_and(|file| file.disk_state().exists());
18922        diff.update(cx, |diff, cx| {
18923            diff.stage_or_unstage_hunks(
18924                stage,
18925                &hunks
18926                    .map(|hunk| buffer_diff::DiffHunk {
18927                        buffer_range: hunk.buffer_range,
18928                        diff_base_byte_range: hunk.diff_base_byte_range,
18929                        secondary_status: hunk.secondary_status,
18930                        range: Point::zero()..Point::zero(), // unused
18931                    })
18932                    .collect::<Vec<_>>(),
18933                &buffer_snapshot,
18934                file_exists,
18935                cx,
18936            )
18937        });
18938        None
18939    }
18940
18941    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18942        let ranges: Vec<_> = self
18943            .selections
18944            .disjoint_anchors()
18945            .iter()
18946            .map(|s| s.range())
18947            .collect();
18948        self.buffer
18949            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18950    }
18951
18952    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18953        self.buffer.update(cx, |buffer, cx| {
18954            let ranges = vec![Anchor::min()..Anchor::max()];
18955            if !buffer.all_diff_hunks_expanded()
18956                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18957            {
18958                buffer.collapse_diff_hunks(ranges, cx);
18959                true
18960            } else {
18961                false
18962            }
18963        })
18964    }
18965
18966    fn toggle_diff_hunks_in_ranges(
18967        &mut self,
18968        ranges: Vec<Range<Anchor>>,
18969        cx: &mut Context<Editor>,
18970    ) {
18971        self.buffer.update(cx, |buffer, cx| {
18972            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18973            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18974        })
18975    }
18976
18977    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18978        self.buffer.update(cx, |buffer, cx| {
18979            let snapshot = buffer.snapshot(cx);
18980            let excerpt_id = range.end.excerpt_id;
18981            let point_range = range.to_point(&snapshot);
18982            let expand = !buffer.single_hunk_is_expanded(range, cx);
18983            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18984        })
18985    }
18986
18987    pub(crate) fn apply_all_diff_hunks(
18988        &mut self,
18989        _: &ApplyAllDiffHunks,
18990        window: &mut Window,
18991        cx: &mut Context<Self>,
18992    ) {
18993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18994
18995        let buffers = self.buffer.read(cx).all_buffers();
18996        for branch_buffer in buffers {
18997            branch_buffer.update(cx, |branch_buffer, cx| {
18998                branch_buffer.merge_into_base(Vec::new(), cx);
18999            });
19000        }
19001
19002        if let Some(project) = self.project.clone() {
19003            self.save(
19004                SaveOptions {
19005                    format: true,
19006                    autosave: false,
19007                },
19008                project,
19009                window,
19010                cx,
19011            )
19012            .detach_and_log_err(cx);
19013        }
19014    }
19015
19016    pub(crate) fn apply_selected_diff_hunks(
19017        &mut self,
19018        _: &ApplyDiffHunk,
19019        window: &mut Window,
19020        cx: &mut Context<Self>,
19021    ) {
19022        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19023        let snapshot = self.snapshot(window, cx);
19024        let hunks = snapshot.hunks_for_ranges(
19025            self.selections
19026                .all(cx)
19027                .into_iter()
19028                .map(|selection| selection.range()),
19029        );
19030        let mut ranges_by_buffer = HashMap::default();
19031        self.transact(window, cx, |editor, _window, cx| {
19032            for hunk in hunks {
19033                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19034                    ranges_by_buffer
19035                        .entry(buffer.clone())
19036                        .or_insert_with(Vec::new)
19037                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19038                }
19039            }
19040
19041            for (buffer, ranges) in ranges_by_buffer {
19042                buffer.update(cx, |buffer, cx| {
19043                    buffer.merge_into_base(ranges, cx);
19044                });
19045            }
19046        });
19047
19048        if let Some(project) = self.project.clone() {
19049            self.save(
19050                SaveOptions {
19051                    format: true,
19052                    autosave: false,
19053                },
19054                project,
19055                window,
19056                cx,
19057            )
19058            .detach_and_log_err(cx);
19059        }
19060    }
19061
19062    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19063        if hovered != self.gutter_hovered {
19064            self.gutter_hovered = hovered;
19065            cx.notify();
19066        }
19067    }
19068
19069    pub fn insert_blocks(
19070        &mut self,
19071        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19072        autoscroll: Option<Autoscroll>,
19073        cx: &mut Context<Self>,
19074    ) -> Vec<CustomBlockId> {
19075        let blocks = self
19076            .display_map
19077            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19078        if let Some(autoscroll) = autoscroll {
19079            self.request_autoscroll(autoscroll, cx);
19080        }
19081        cx.notify();
19082        blocks
19083    }
19084
19085    pub fn resize_blocks(
19086        &mut self,
19087        heights: HashMap<CustomBlockId, u32>,
19088        autoscroll: Option<Autoscroll>,
19089        cx: &mut Context<Self>,
19090    ) {
19091        self.display_map
19092            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19093        if let Some(autoscroll) = autoscroll {
19094            self.request_autoscroll(autoscroll, cx);
19095        }
19096        cx.notify();
19097    }
19098
19099    pub fn replace_blocks(
19100        &mut self,
19101        renderers: HashMap<CustomBlockId, RenderBlock>,
19102        autoscroll: Option<Autoscroll>,
19103        cx: &mut Context<Self>,
19104    ) {
19105        self.display_map
19106            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19107        if let Some(autoscroll) = autoscroll {
19108            self.request_autoscroll(autoscroll, cx);
19109        }
19110        cx.notify();
19111    }
19112
19113    pub fn remove_blocks(
19114        &mut self,
19115        block_ids: HashSet<CustomBlockId>,
19116        autoscroll: Option<Autoscroll>,
19117        cx: &mut Context<Self>,
19118    ) {
19119        self.display_map.update(cx, |display_map, cx| {
19120            display_map.remove_blocks(block_ids, cx)
19121        });
19122        if let Some(autoscroll) = autoscroll {
19123            self.request_autoscroll(autoscroll, cx);
19124        }
19125        cx.notify();
19126    }
19127
19128    pub fn row_for_block(
19129        &self,
19130        block_id: CustomBlockId,
19131        cx: &mut Context<Self>,
19132    ) -> Option<DisplayRow> {
19133        self.display_map
19134            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19135    }
19136
19137    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19138        self.focused_block = Some(focused_block);
19139    }
19140
19141    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19142        self.focused_block.take()
19143    }
19144
19145    pub fn insert_creases(
19146        &mut self,
19147        creases: impl IntoIterator<Item = Crease<Anchor>>,
19148        cx: &mut Context<Self>,
19149    ) -> Vec<CreaseId> {
19150        self.display_map
19151            .update(cx, |map, cx| map.insert_creases(creases, cx))
19152    }
19153
19154    pub fn remove_creases(
19155        &mut self,
19156        ids: impl IntoIterator<Item = CreaseId>,
19157        cx: &mut Context<Self>,
19158    ) -> Vec<(CreaseId, Range<Anchor>)> {
19159        self.display_map
19160            .update(cx, |map, cx| map.remove_creases(ids, cx))
19161    }
19162
19163    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19164        self.display_map
19165            .update(cx, |map, cx| map.snapshot(cx))
19166            .longest_row()
19167    }
19168
19169    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19170        self.display_map
19171            .update(cx, |map, cx| map.snapshot(cx))
19172            .max_point()
19173    }
19174
19175    pub fn text(&self, cx: &App) -> String {
19176        self.buffer.read(cx).read(cx).text()
19177    }
19178
19179    pub fn is_empty(&self, cx: &App) -> bool {
19180        self.buffer.read(cx).read(cx).is_empty()
19181    }
19182
19183    pub fn text_option(&self, cx: &App) -> Option<String> {
19184        let text = self.text(cx);
19185        let text = text.trim();
19186
19187        if text.is_empty() {
19188            return None;
19189        }
19190
19191        Some(text.to_string())
19192    }
19193
19194    pub fn set_text(
19195        &mut self,
19196        text: impl Into<Arc<str>>,
19197        window: &mut Window,
19198        cx: &mut Context<Self>,
19199    ) {
19200        self.transact(window, cx, |this, _, cx| {
19201            this.buffer
19202                .read(cx)
19203                .as_singleton()
19204                .expect("you can only call set_text on editors for singleton buffers")
19205                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19206        });
19207    }
19208
19209    pub fn display_text(&self, cx: &mut App) -> String {
19210        self.display_map
19211            .update(cx, |map, cx| map.snapshot(cx))
19212            .text()
19213    }
19214
19215    fn create_minimap(
19216        &self,
19217        minimap_settings: MinimapSettings,
19218        window: &mut Window,
19219        cx: &mut Context<Self>,
19220    ) -> Option<Entity<Self>> {
19221        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19222            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19223    }
19224
19225    fn initialize_new_minimap(
19226        &self,
19227        minimap_settings: MinimapSettings,
19228        window: &mut Window,
19229        cx: &mut Context<Self>,
19230    ) -> Entity<Self> {
19231        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19232
19233        let mut minimap = Editor::new_internal(
19234            EditorMode::Minimap {
19235                parent: cx.weak_entity(),
19236            },
19237            self.buffer.clone(),
19238            None,
19239            Some(self.display_map.clone()),
19240            window,
19241            cx,
19242        );
19243        minimap.scroll_manager.clone_state(&self.scroll_manager);
19244        minimap.set_text_style_refinement(TextStyleRefinement {
19245            font_size: Some(MINIMAP_FONT_SIZE),
19246            font_weight: Some(MINIMAP_FONT_WEIGHT),
19247            ..Default::default()
19248        });
19249        minimap.update_minimap_configuration(minimap_settings, cx);
19250        cx.new(|_| minimap)
19251    }
19252
19253    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19254        let current_line_highlight = minimap_settings
19255            .current_line_highlight
19256            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19257        self.set_current_line_highlight(Some(current_line_highlight));
19258    }
19259
19260    pub fn minimap(&self) -> Option<&Entity<Self>> {
19261        self.minimap
19262            .as_ref()
19263            .filter(|_| self.minimap_visibility.visible())
19264    }
19265
19266    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19267        let mut wrap_guides = smallvec![];
19268
19269        if self.show_wrap_guides == Some(false) {
19270            return wrap_guides;
19271        }
19272
19273        let settings = self.buffer.read(cx).language_settings(cx);
19274        if settings.show_wrap_guides {
19275            match self.soft_wrap_mode(cx) {
19276                SoftWrap::Column(soft_wrap) => {
19277                    wrap_guides.push((soft_wrap as usize, true));
19278                }
19279                SoftWrap::Bounded(soft_wrap) => {
19280                    wrap_guides.push((soft_wrap as usize, true));
19281                }
19282                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19283            }
19284            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19285        }
19286
19287        wrap_guides
19288    }
19289
19290    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19291        let settings = self.buffer.read(cx).language_settings(cx);
19292        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19293        match mode {
19294            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19295                SoftWrap::None
19296            }
19297            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19298            language_settings::SoftWrap::PreferredLineLength => {
19299                SoftWrap::Column(settings.preferred_line_length)
19300            }
19301            language_settings::SoftWrap::Bounded => {
19302                SoftWrap::Bounded(settings.preferred_line_length)
19303            }
19304        }
19305    }
19306
19307    pub fn set_soft_wrap_mode(
19308        &mut self,
19309        mode: language_settings::SoftWrap,
19310
19311        cx: &mut Context<Self>,
19312    ) {
19313        self.soft_wrap_mode_override = Some(mode);
19314        cx.notify();
19315    }
19316
19317    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19318        self.hard_wrap = hard_wrap;
19319        cx.notify();
19320    }
19321
19322    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19323        self.text_style_refinement = Some(style);
19324    }
19325
19326    /// called by the Element so we know what style we were most recently rendered with.
19327    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19328        // We intentionally do not inform the display map about the minimap style
19329        // so that wrapping is not recalculated and stays consistent for the editor
19330        // and its linked minimap.
19331        if !self.mode.is_minimap() {
19332            let font = style.text.font();
19333            let font_size = style.text.font_size.to_pixels(window.rem_size());
19334            let display_map = self
19335                .placeholder_display_map
19336                .as_ref()
19337                .filter(|_| self.is_empty(cx))
19338                .unwrap_or(&self.display_map);
19339
19340            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19341        }
19342        self.style = Some(style);
19343    }
19344
19345    pub fn style(&self) -> Option<&EditorStyle> {
19346        self.style.as_ref()
19347    }
19348
19349    // Called by the element. This method is not designed to be called outside of the editor
19350    // element's layout code because it does not notify when rewrapping is computed synchronously.
19351    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19352        if self.is_empty(cx) {
19353            self.placeholder_display_map
19354                .as_ref()
19355                .map_or(false, |display_map| {
19356                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19357                })
19358        } else {
19359            self.display_map
19360                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19361        }
19362    }
19363
19364    pub fn set_soft_wrap(&mut self) {
19365        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19366    }
19367
19368    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19369        if self.soft_wrap_mode_override.is_some() {
19370            self.soft_wrap_mode_override.take();
19371        } else {
19372            let soft_wrap = match self.soft_wrap_mode(cx) {
19373                SoftWrap::GitDiff => return,
19374                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19375                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19376                    language_settings::SoftWrap::None
19377                }
19378            };
19379            self.soft_wrap_mode_override = Some(soft_wrap);
19380        }
19381        cx.notify();
19382    }
19383
19384    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19385        let Some(workspace) = self.workspace() else {
19386            return;
19387        };
19388        let fs = workspace.read(cx).app_state().fs.clone();
19389        let current_show = TabBarSettings::get_global(cx).show;
19390        update_settings_file(fs, cx, move |setting, _| {
19391            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19392        });
19393    }
19394
19395    pub fn toggle_indent_guides(
19396        &mut self,
19397        _: &ToggleIndentGuides,
19398        _: &mut Window,
19399        cx: &mut Context<Self>,
19400    ) {
19401        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19402            self.buffer
19403                .read(cx)
19404                .language_settings(cx)
19405                .indent_guides
19406                .enabled
19407        });
19408        self.show_indent_guides = Some(!currently_enabled);
19409        cx.notify();
19410    }
19411
19412    fn should_show_indent_guides(&self) -> Option<bool> {
19413        self.show_indent_guides
19414    }
19415
19416    pub fn toggle_line_numbers(
19417        &mut self,
19418        _: &ToggleLineNumbers,
19419        _: &mut Window,
19420        cx: &mut Context<Self>,
19421    ) {
19422        let mut editor_settings = EditorSettings::get_global(cx).clone();
19423        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19424        EditorSettings::override_global(editor_settings, cx);
19425    }
19426
19427    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19428        if let Some(show_line_numbers) = self.show_line_numbers {
19429            return show_line_numbers;
19430        }
19431        EditorSettings::get_global(cx).gutter.line_numbers
19432    }
19433
19434    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19435        self.use_relative_line_numbers
19436            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19437    }
19438
19439    pub fn toggle_relative_line_numbers(
19440        &mut self,
19441        _: &ToggleRelativeLineNumbers,
19442        _: &mut Window,
19443        cx: &mut Context<Self>,
19444    ) {
19445        let is_relative = self.should_use_relative_line_numbers(cx);
19446        self.set_relative_line_number(Some(!is_relative), cx)
19447    }
19448
19449    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19450        self.use_relative_line_numbers = is_relative;
19451        cx.notify();
19452    }
19453
19454    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19455        self.show_gutter = show_gutter;
19456        cx.notify();
19457    }
19458
19459    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19460        self.show_scrollbars = ScrollbarAxes {
19461            horizontal: show,
19462            vertical: show,
19463        };
19464        cx.notify();
19465    }
19466
19467    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19468        self.show_scrollbars.vertical = show;
19469        cx.notify();
19470    }
19471
19472    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19473        self.show_scrollbars.horizontal = show;
19474        cx.notify();
19475    }
19476
19477    pub fn set_minimap_visibility(
19478        &mut self,
19479        minimap_visibility: MinimapVisibility,
19480        window: &mut Window,
19481        cx: &mut Context<Self>,
19482    ) {
19483        if self.minimap_visibility != minimap_visibility {
19484            if minimap_visibility.visible() && self.minimap.is_none() {
19485                let minimap_settings = EditorSettings::get_global(cx).minimap;
19486                self.minimap =
19487                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19488            }
19489            self.minimap_visibility = minimap_visibility;
19490            cx.notify();
19491        }
19492    }
19493
19494    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19495        self.set_show_scrollbars(false, cx);
19496        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19497    }
19498
19499    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19500        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19501    }
19502
19503    /// Normally the text in full mode and auto height editors is padded on the
19504    /// left side by roughly half a character width for improved hit testing.
19505    ///
19506    /// Use this method to disable this for cases where this is not wanted (e.g.
19507    /// if you want to align the editor text with some other text above or below)
19508    /// or if you want to add this padding to single-line editors.
19509    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19510        self.offset_content = offset_content;
19511        cx.notify();
19512    }
19513
19514    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19515        self.show_line_numbers = Some(show_line_numbers);
19516        cx.notify();
19517    }
19518
19519    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19520        self.disable_expand_excerpt_buttons = true;
19521        cx.notify();
19522    }
19523
19524    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19525        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19526        cx.notify();
19527    }
19528
19529    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19530        self.show_code_actions = Some(show_code_actions);
19531        cx.notify();
19532    }
19533
19534    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19535        self.show_runnables = Some(show_runnables);
19536        cx.notify();
19537    }
19538
19539    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19540        self.show_breakpoints = Some(show_breakpoints);
19541        cx.notify();
19542    }
19543
19544    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19545        if self.display_map.read(cx).masked != masked {
19546            self.display_map.update(cx, |map, _| map.masked = masked);
19547        }
19548        cx.notify()
19549    }
19550
19551    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19552        self.show_wrap_guides = Some(show_wrap_guides);
19553        cx.notify();
19554    }
19555
19556    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19557        self.show_indent_guides = Some(show_indent_guides);
19558        cx.notify();
19559    }
19560
19561    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19562        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19563            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19564                && let Some(dir) = file.abs_path(cx).parent()
19565            {
19566                return Some(dir.to_owned());
19567            }
19568        }
19569
19570        None
19571    }
19572
19573    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19574        self.active_excerpt(cx)?
19575            .1
19576            .read(cx)
19577            .file()
19578            .and_then(|f| f.as_local())
19579    }
19580
19581    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19582        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19583            let buffer = buffer.read(cx);
19584            if let Some(project_path) = buffer.project_path(cx) {
19585                let project = self.project()?.read(cx);
19586                project.absolute_path(&project_path, cx)
19587            } else {
19588                buffer
19589                    .file()
19590                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19591            }
19592        })
19593    }
19594
19595    pub fn reveal_in_finder(
19596        &mut self,
19597        _: &RevealInFileManager,
19598        _window: &mut Window,
19599        cx: &mut Context<Self>,
19600    ) {
19601        if let Some(target) = self.target_file(cx) {
19602            cx.reveal_path(&target.abs_path(cx));
19603        }
19604    }
19605
19606    pub fn copy_path(
19607        &mut self,
19608        _: &zed_actions::workspace::CopyPath,
19609        _window: &mut Window,
19610        cx: &mut Context<Self>,
19611    ) {
19612        if let Some(path) = self.target_file_abs_path(cx)
19613            && let Some(path) = path.to_str()
19614        {
19615            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19616        } else {
19617            cx.propagate();
19618        }
19619    }
19620
19621    pub fn copy_relative_path(
19622        &mut self,
19623        _: &zed_actions::workspace::CopyRelativePath,
19624        _window: &mut Window,
19625        cx: &mut Context<Self>,
19626    ) {
19627        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19628            let project = self.project()?.read(cx);
19629            let path = buffer.read(cx).file()?.path();
19630            let path = path.display(project.path_style(cx));
19631            Some(path)
19632        }) {
19633            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19634        } else {
19635            cx.propagate();
19636        }
19637    }
19638
19639    /// Returns the project path for the editor's buffer, if any buffer is
19640    /// opened in the editor.
19641    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19642        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19643            buffer.read(cx).project_path(cx)
19644        } else {
19645            None
19646        }
19647    }
19648
19649    // Returns true if the editor handled a go-to-line request
19650    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19651        maybe!({
19652            let breakpoint_store = self.breakpoint_store.as_ref()?;
19653
19654            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19655            else {
19656                self.clear_row_highlights::<ActiveDebugLine>();
19657                return None;
19658            };
19659
19660            let position = active_stack_frame.position;
19661            let buffer_id = position.buffer_id?;
19662            let snapshot = self
19663                .project
19664                .as_ref()?
19665                .read(cx)
19666                .buffer_for_id(buffer_id, cx)?
19667                .read(cx)
19668                .snapshot();
19669
19670            let mut handled = false;
19671            for (id, ExcerptRange { context, .. }) in
19672                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19673            {
19674                if context.start.cmp(&position, &snapshot).is_ge()
19675                    || context.end.cmp(&position, &snapshot).is_lt()
19676                {
19677                    continue;
19678                }
19679                let snapshot = self.buffer.read(cx).snapshot(cx);
19680                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19681
19682                handled = true;
19683                self.clear_row_highlights::<ActiveDebugLine>();
19684
19685                self.go_to_line::<ActiveDebugLine>(
19686                    multibuffer_anchor,
19687                    Some(cx.theme().colors().editor_debugger_active_line_background),
19688                    window,
19689                    cx,
19690                );
19691
19692                cx.notify();
19693            }
19694
19695            handled.then_some(())
19696        })
19697        .is_some()
19698    }
19699
19700    pub fn copy_file_name_without_extension(
19701        &mut self,
19702        _: &CopyFileNameWithoutExtension,
19703        _: &mut Window,
19704        cx: &mut Context<Self>,
19705    ) {
19706        if let Some(file) = self.target_file(cx)
19707            && let Some(file_stem) = file.path().file_stem()
19708        {
19709            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19710        }
19711    }
19712
19713    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19714        if let Some(file) = self.target_file(cx)
19715            && let Some(name) = file.path().file_name()
19716        {
19717            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19718        }
19719    }
19720
19721    pub fn toggle_git_blame(
19722        &mut self,
19723        _: &::git::Blame,
19724        window: &mut Window,
19725        cx: &mut Context<Self>,
19726    ) {
19727        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19728
19729        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19730            self.start_git_blame(true, window, cx);
19731        }
19732
19733        cx.notify();
19734    }
19735
19736    pub fn toggle_git_blame_inline(
19737        &mut self,
19738        _: &ToggleGitBlameInline,
19739        window: &mut Window,
19740        cx: &mut Context<Self>,
19741    ) {
19742        self.toggle_git_blame_inline_internal(true, window, cx);
19743        cx.notify();
19744    }
19745
19746    pub fn open_git_blame_commit(
19747        &mut self,
19748        _: &OpenGitBlameCommit,
19749        window: &mut Window,
19750        cx: &mut Context<Self>,
19751    ) {
19752        self.open_git_blame_commit_internal(window, cx);
19753    }
19754
19755    fn open_git_blame_commit_internal(
19756        &mut self,
19757        window: &mut Window,
19758        cx: &mut Context<Self>,
19759    ) -> Option<()> {
19760        let blame = self.blame.as_ref()?;
19761        let snapshot = self.snapshot(window, cx);
19762        let cursor = self.selections.newest::<Point>(cx).head();
19763        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19764        let (_, blame_entry) = blame
19765            .update(cx, |blame, cx| {
19766                blame
19767                    .blame_for_rows(
19768                        &[RowInfo {
19769                            buffer_id: Some(buffer.remote_id()),
19770                            buffer_row: Some(point.row),
19771                            ..Default::default()
19772                        }],
19773                        cx,
19774                    )
19775                    .next()
19776            })
19777            .flatten()?;
19778        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19779        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19780        let workspace = self.workspace()?.downgrade();
19781        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19782        None
19783    }
19784
19785    pub fn git_blame_inline_enabled(&self) -> bool {
19786        self.git_blame_inline_enabled
19787    }
19788
19789    pub fn toggle_selection_menu(
19790        &mut self,
19791        _: &ToggleSelectionMenu,
19792        _: &mut Window,
19793        cx: &mut Context<Self>,
19794    ) {
19795        self.show_selection_menu = self
19796            .show_selection_menu
19797            .map(|show_selections_menu| !show_selections_menu)
19798            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19799
19800        cx.notify();
19801    }
19802
19803    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19804        self.show_selection_menu
19805            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19806    }
19807
19808    fn start_git_blame(
19809        &mut self,
19810        user_triggered: bool,
19811        window: &mut Window,
19812        cx: &mut Context<Self>,
19813    ) {
19814        if let Some(project) = self.project() {
19815            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19816                && buffer.read(cx).file().is_none()
19817            {
19818                return;
19819            }
19820
19821            let focused = self.focus_handle(cx).contains_focused(window, cx);
19822
19823            let project = project.clone();
19824            let blame = cx
19825                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19826            self.blame_subscription =
19827                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19828            self.blame = Some(blame);
19829        }
19830    }
19831
19832    fn toggle_git_blame_inline_internal(
19833        &mut self,
19834        user_triggered: bool,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        if self.git_blame_inline_enabled {
19839            self.git_blame_inline_enabled = false;
19840            self.show_git_blame_inline = false;
19841            self.show_git_blame_inline_delay_task.take();
19842        } else {
19843            self.git_blame_inline_enabled = true;
19844            self.start_git_blame_inline(user_triggered, window, cx);
19845        }
19846
19847        cx.notify();
19848    }
19849
19850    fn start_git_blame_inline(
19851        &mut self,
19852        user_triggered: bool,
19853        window: &mut Window,
19854        cx: &mut Context<Self>,
19855    ) {
19856        self.start_git_blame(user_triggered, window, cx);
19857
19858        if ProjectSettings::get_global(cx)
19859            .git
19860            .inline_blame_delay()
19861            .is_some()
19862        {
19863            self.start_inline_blame_timer(window, cx);
19864        } else {
19865            self.show_git_blame_inline = true
19866        }
19867    }
19868
19869    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19870        self.blame.as_ref()
19871    }
19872
19873    pub fn show_git_blame_gutter(&self) -> bool {
19874        self.show_git_blame_gutter
19875    }
19876
19877    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19878        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19879    }
19880
19881    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19882        self.show_git_blame_inline
19883            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19884            && !self.newest_selection_head_on_empty_line(cx)
19885            && self.has_blame_entries(cx)
19886    }
19887
19888    fn has_blame_entries(&self, cx: &App) -> bool {
19889        self.blame()
19890            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19891    }
19892
19893    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19894        let cursor_anchor = self.selections.newest_anchor().head();
19895
19896        let snapshot = self.buffer.read(cx).snapshot(cx);
19897        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19898
19899        snapshot.line_len(buffer_row) == 0
19900    }
19901
19902    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19903        let buffer_and_selection = maybe!({
19904            let selection = self.selections.newest::<Point>(cx);
19905            let selection_range = selection.range();
19906
19907            let multi_buffer = self.buffer().read(cx);
19908            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19909            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19910
19911            let (buffer, range, _) = if selection.reversed {
19912                buffer_ranges.first()
19913            } else {
19914                buffer_ranges.last()
19915            }?;
19916
19917            let selection = text::ToPoint::to_point(&range.start, buffer).row
19918                ..text::ToPoint::to_point(&range.end, buffer).row;
19919            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19920        });
19921
19922        let Some((buffer, selection)) = buffer_and_selection else {
19923            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19924        };
19925
19926        let Some(project) = self.project() else {
19927            return Task::ready(Err(anyhow!("editor does not have project")));
19928        };
19929
19930        project.update(cx, |project, cx| {
19931            project.get_permalink_to_line(&buffer, selection, cx)
19932        })
19933    }
19934
19935    pub fn copy_permalink_to_line(
19936        &mut self,
19937        _: &CopyPermalinkToLine,
19938        window: &mut Window,
19939        cx: &mut Context<Self>,
19940    ) {
19941        let permalink_task = self.get_permalink_to_line(cx);
19942        let workspace = self.workspace();
19943
19944        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19945            Ok(permalink) => {
19946                cx.update(|_, cx| {
19947                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19948                })
19949                .ok();
19950            }
19951            Err(err) => {
19952                let message = format!("Failed to copy permalink: {err}");
19953
19954                anyhow::Result::<()>::Err(err).log_err();
19955
19956                if let Some(workspace) = workspace {
19957                    workspace
19958                        .update_in(cx, |workspace, _, cx| {
19959                            struct CopyPermalinkToLine;
19960
19961                            workspace.show_toast(
19962                                Toast::new(
19963                                    NotificationId::unique::<CopyPermalinkToLine>(),
19964                                    message,
19965                                ),
19966                                cx,
19967                            )
19968                        })
19969                        .ok();
19970                }
19971            }
19972        })
19973        .detach();
19974    }
19975
19976    pub fn copy_file_location(
19977        &mut self,
19978        _: &CopyFileLocation,
19979        _: &mut Window,
19980        cx: &mut Context<Self>,
19981    ) {
19982        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19983        if let Some(file) = self.target_file(cx) {
19984            let path = file.path().display(file.path_style(cx));
19985            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19986        }
19987    }
19988
19989    pub fn open_permalink_to_line(
19990        &mut self,
19991        _: &OpenPermalinkToLine,
19992        window: &mut Window,
19993        cx: &mut Context<Self>,
19994    ) {
19995        let permalink_task = self.get_permalink_to_line(cx);
19996        let workspace = self.workspace();
19997
19998        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19999            Ok(permalink) => {
20000                cx.update(|_, cx| {
20001                    cx.open_url(permalink.as_ref());
20002                })
20003                .ok();
20004            }
20005            Err(err) => {
20006                let message = format!("Failed to open permalink: {err}");
20007
20008                anyhow::Result::<()>::Err(err).log_err();
20009
20010                if let Some(workspace) = workspace {
20011                    workspace
20012                        .update(cx, |workspace, cx| {
20013                            struct OpenPermalinkToLine;
20014
20015                            workspace.show_toast(
20016                                Toast::new(
20017                                    NotificationId::unique::<OpenPermalinkToLine>(),
20018                                    message,
20019                                ),
20020                                cx,
20021                            )
20022                        })
20023                        .ok();
20024                }
20025            }
20026        })
20027        .detach();
20028    }
20029
20030    pub fn insert_uuid_v4(
20031        &mut self,
20032        _: &InsertUuidV4,
20033        window: &mut Window,
20034        cx: &mut Context<Self>,
20035    ) {
20036        self.insert_uuid(UuidVersion::V4, window, cx);
20037    }
20038
20039    pub fn insert_uuid_v7(
20040        &mut self,
20041        _: &InsertUuidV7,
20042        window: &mut Window,
20043        cx: &mut Context<Self>,
20044    ) {
20045        self.insert_uuid(UuidVersion::V7, window, cx);
20046    }
20047
20048    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20049        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20050        self.transact(window, cx, |this, window, cx| {
20051            let edits = this
20052                .selections
20053                .all::<Point>(cx)
20054                .into_iter()
20055                .map(|selection| {
20056                    let uuid = match version {
20057                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20058                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20059                    };
20060
20061                    (selection.range(), uuid.to_string())
20062                });
20063            this.edit(edits, cx);
20064            this.refresh_edit_prediction(true, false, window, cx);
20065        });
20066    }
20067
20068    pub fn open_selections_in_multibuffer(
20069        &mut self,
20070        _: &OpenSelectionsInMultibuffer,
20071        window: &mut Window,
20072        cx: &mut Context<Self>,
20073    ) {
20074        let multibuffer = self.buffer.read(cx);
20075
20076        let Some(buffer) = multibuffer.as_singleton() else {
20077            return;
20078        };
20079
20080        let Some(workspace) = self.workspace() else {
20081            return;
20082        };
20083
20084        let title = multibuffer.title(cx).to_string();
20085
20086        let locations = self
20087            .selections
20088            .all_anchors(cx)
20089            .iter()
20090            .map(|selection| {
20091                (
20092                    buffer.clone(),
20093                    (selection.start.text_anchor..selection.end.text_anchor)
20094                        .to_point(buffer.read(cx)),
20095                )
20096            })
20097            .into_group_map();
20098
20099        cx.spawn_in(window, async move |_, cx| {
20100            workspace.update_in(cx, |workspace, window, cx| {
20101                Self::open_locations_in_multibuffer(
20102                    workspace,
20103                    locations,
20104                    format!("Selections for '{title}'"),
20105                    false,
20106                    MultibufferSelectionMode::All,
20107                    window,
20108                    cx,
20109                );
20110            })
20111        })
20112        .detach();
20113    }
20114
20115    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20116    /// last highlight added will be used.
20117    ///
20118    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20119    pub fn highlight_rows<T: 'static>(
20120        &mut self,
20121        range: Range<Anchor>,
20122        color: Hsla,
20123        options: RowHighlightOptions,
20124        cx: &mut Context<Self>,
20125    ) {
20126        let snapshot = self.buffer().read(cx).snapshot(cx);
20127        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20128        let ix = row_highlights.binary_search_by(|highlight| {
20129            Ordering::Equal
20130                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20131                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20132        });
20133
20134        if let Err(mut ix) = ix {
20135            let index = post_inc(&mut self.highlight_order);
20136
20137            // If this range intersects with the preceding highlight, then merge it with
20138            // the preceding highlight. Otherwise insert a new highlight.
20139            let mut merged = false;
20140            if ix > 0 {
20141                let prev_highlight = &mut row_highlights[ix - 1];
20142                if prev_highlight
20143                    .range
20144                    .end
20145                    .cmp(&range.start, &snapshot)
20146                    .is_ge()
20147                {
20148                    ix -= 1;
20149                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20150                        prev_highlight.range.end = range.end;
20151                    }
20152                    merged = true;
20153                    prev_highlight.index = index;
20154                    prev_highlight.color = color;
20155                    prev_highlight.options = options;
20156                }
20157            }
20158
20159            if !merged {
20160                row_highlights.insert(
20161                    ix,
20162                    RowHighlight {
20163                        range,
20164                        index,
20165                        color,
20166                        options,
20167                        type_id: TypeId::of::<T>(),
20168                    },
20169                );
20170            }
20171
20172            // If any of the following highlights intersect with this one, merge them.
20173            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20174                let highlight = &row_highlights[ix];
20175                if next_highlight
20176                    .range
20177                    .start
20178                    .cmp(&highlight.range.end, &snapshot)
20179                    .is_le()
20180                {
20181                    if next_highlight
20182                        .range
20183                        .end
20184                        .cmp(&highlight.range.end, &snapshot)
20185                        .is_gt()
20186                    {
20187                        row_highlights[ix].range.end = next_highlight.range.end;
20188                    }
20189                    row_highlights.remove(ix + 1);
20190                } else {
20191                    break;
20192                }
20193            }
20194        }
20195    }
20196
20197    /// Remove any highlighted row ranges of the given type that intersect the
20198    /// given ranges.
20199    pub fn remove_highlighted_rows<T: 'static>(
20200        &mut self,
20201        ranges_to_remove: Vec<Range<Anchor>>,
20202        cx: &mut Context<Self>,
20203    ) {
20204        let snapshot = self.buffer().read(cx).snapshot(cx);
20205        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20206        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20207        row_highlights.retain(|highlight| {
20208            while let Some(range_to_remove) = ranges_to_remove.peek() {
20209                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20210                    Ordering::Less | Ordering::Equal => {
20211                        ranges_to_remove.next();
20212                    }
20213                    Ordering::Greater => {
20214                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20215                            Ordering::Less | Ordering::Equal => {
20216                                return false;
20217                            }
20218                            Ordering::Greater => break,
20219                        }
20220                    }
20221                }
20222            }
20223
20224            true
20225        })
20226    }
20227
20228    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20229    pub fn clear_row_highlights<T: 'static>(&mut self) {
20230        self.highlighted_rows.remove(&TypeId::of::<T>());
20231    }
20232
20233    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20234    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20235        self.highlighted_rows
20236            .get(&TypeId::of::<T>())
20237            .map_or(&[] as &[_], |vec| vec.as_slice())
20238            .iter()
20239            .map(|highlight| (highlight.range.clone(), highlight.color))
20240    }
20241
20242    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20243    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20244    /// Allows to ignore certain kinds of highlights.
20245    pub fn highlighted_display_rows(
20246        &self,
20247        window: &mut Window,
20248        cx: &mut App,
20249    ) -> BTreeMap<DisplayRow, LineHighlight> {
20250        let snapshot = self.snapshot(window, cx);
20251        let mut used_highlight_orders = HashMap::default();
20252        self.highlighted_rows
20253            .iter()
20254            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20255            .fold(
20256                BTreeMap::<DisplayRow, LineHighlight>::new(),
20257                |mut unique_rows, highlight| {
20258                    let start = highlight.range.start.to_display_point(&snapshot);
20259                    let end = highlight.range.end.to_display_point(&snapshot);
20260                    let start_row = start.row().0;
20261                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20262                        && end.column() == 0
20263                    {
20264                        end.row().0.saturating_sub(1)
20265                    } else {
20266                        end.row().0
20267                    };
20268                    for row in start_row..=end_row {
20269                        let used_index =
20270                            used_highlight_orders.entry(row).or_insert(highlight.index);
20271                        if highlight.index >= *used_index {
20272                            *used_index = highlight.index;
20273                            unique_rows.insert(
20274                                DisplayRow(row),
20275                                LineHighlight {
20276                                    include_gutter: highlight.options.include_gutter,
20277                                    border: None,
20278                                    background: highlight.color.into(),
20279                                    type_id: Some(highlight.type_id),
20280                                },
20281                            );
20282                        }
20283                    }
20284                    unique_rows
20285                },
20286            )
20287    }
20288
20289    pub fn highlighted_display_row_for_autoscroll(
20290        &self,
20291        snapshot: &DisplaySnapshot,
20292    ) -> Option<DisplayRow> {
20293        self.highlighted_rows
20294            .values()
20295            .flat_map(|highlighted_rows| highlighted_rows.iter())
20296            .filter_map(|highlight| {
20297                if highlight.options.autoscroll {
20298                    Some(highlight.range.start.to_display_point(snapshot).row())
20299                } else {
20300                    None
20301                }
20302            })
20303            .min()
20304    }
20305
20306    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20307        self.highlight_background::<SearchWithinRange>(
20308            ranges,
20309            |colors| colors.colors().editor_document_highlight_read_background,
20310            cx,
20311        )
20312    }
20313
20314    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20315        self.breadcrumb_header = Some(new_header);
20316    }
20317
20318    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20319        self.clear_background_highlights::<SearchWithinRange>(cx);
20320    }
20321
20322    pub fn highlight_background<T: 'static>(
20323        &mut self,
20324        ranges: &[Range<Anchor>],
20325        color_fetcher: fn(&Theme) -> Hsla,
20326        cx: &mut Context<Self>,
20327    ) {
20328        self.background_highlights.insert(
20329            HighlightKey::Type(TypeId::of::<T>()),
20330            (color_fetcher, Arc::from(ranges)),
20331        );
20332        self.scrollbar_marker_state.dirty = true;
20333        cx.notify();
20334    }
20335
20336    pub fn highlight_background_key<T: 'static>(
20337        &mut self,
20338        key: usize,
20339        ranges: &[Range<Anchor>],
20340        color_fetcher: fn(&Theme) -> Hsla,
20341        cx: &mut Context<Self>,
20342    ) {
20343        self.background_highlights.insert(
20344            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20345            (color_fetcher, Arc::from(ranges)),
20346        );
20347        self.scrollbar_marker_state.dirty = true;
20348        cx.notify();
20349    }
20350
20351    pub fn clear_background_highlights<T: 'static>(
20352        &mut self,
20353        cx: &mut Context<Self>,
20354    ) -> Option<BackgroundHighlight> {
20355        let text_highlights = self
20356            .background_highlights
20357            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20358        if !text_highlights.1.is_empty() {
20359            self.scrollbar_marker_state.dirty = true;
20360            cx.notify();
20361        }
20362        Some(text_highlights)
20363    }
20364
20365    pub fn highlight_gutter<T: 'static>(
20366        &mut self,
20367        ranges: impl Into<Vec<Range<Anchor>>>,
20368        color_fetcher: fn(&App) -> Hsla,
20369        cx: &mut Context<Self>,
20370    ) {
20371        self.gutter_highlights
20372            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20373        cx.notify();
20374    }
20375
20376    pub fn clear_gutter_highlights<T: 'static>(
20377        &mut self,
20378        cx: &mut Context<Self>,
20379    ) -> Option<GutterHighlight> {
20380        cx.notify();
20381        self.gutter_highlights.remove(&TypeId::of::<T>())
20382    }
20383
20384    pub fn insert_gutter_highlight<T: 'static>(
20385        &mut self,
20386        range: Range<Anchor>,
20387        color_fetcher: fn(&App) -> Hsla,
20388        cx: &mut Context<Self>,
20389    ) {
20390        let snapshot = self.buffer().read(cx).snapshot(cx);
20391        let mut highlights = self
20392            .gutter_highlights
20393            .remove(&TypeId::of::<T>())
20394            .map(|(_, highlights)| highlights)
20395            .unwrap_or_default();
20396        let ix = highlights.binary_search_by(|highlight| {
20397            Ordering::Equal
20398                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20399                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20400        });
20401        if let Err(ix) = ix {
20402            highlights.insert(ix, range);
20403        }
20404        self.gutter_highlights
20405            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20406    }
20407
20408    pub fn remove_gutter_highlights<T: 'static>(
20409        &mut self,
20410        ranges_to_remove: Vec<Range<Anchor>>,
20411        cx: &mut Context<Self>,
20412    ) {
20413        let snapshot = self.buffer().read(cx).snapshot(cx);
20414        let Some((color_fetcher, mut gutter_highlights)) =
20415            self.gutter_highlights.remove(&TypeId::of::<T>())
20416        else {
20417            return;
20418        };
20419        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20420        gutter_highlights.retain(|highlight| {
20421            while let Some(range_to_remove) = ranges_to_remove.peek() {
20422                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20423                    Ordering::Less | Ordering::Equal => {
20424                        ranges_to_remove.next();
20425                    }
20426                    Ordering::Greater => {
20427                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20428                            Ordering::Less | Ordering::Equal => {
20429                                return false;
20430                            }
20431                            Ordering::Greater => break,
20432                        }
20433                    }
20434                }
20435            }
20436
20437            true
20438        });
20439        self.gutter_highlights
20440            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20441    }
20442
20443    #[cfg(feature = "test-support")]
20444    pub fn all_text_highlights(
20445        &self,
20446        window: &mut Window,
20447        cx: &mut Context<Self>,
20448    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20449        let snapshot = self.snapshot(window, cx);
20450        self.display_map.update(cx, |display_map, _| {
20451            display_map
20452                .all_text_highlights()
20453                .map(|highlight| {
20454                    let (style, ranges) = highlight.as_ref();
20455                    (
20456                        *style,
20457                        ranges
20458                            .iter()
20459                            .map(|range| range.clone().to_display_points(&snapshot))
20460                            .collect(),
20461                    )
20462                })
20463                .collect()
20464        })
20465    }
20466
20467    #[cfg(feature = "test-support")]
20468    pub fn all_text_background_highlights(
20469        &self,
20470        window: &mut Window,
20471        cx: &mut Context<Self>,
20472    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20473        let snapshot = self.snapshot(window, cx);
20474        let buffer = &snapshot.buffer_snapshot();
20475        let start = buffer.anchor_before(0);
20476        let end = buffer.anchor_after(buffer.len());
20477        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20478    }
20479
20480    #[cfg(any(test, feature = "test-support"))]
20481    pub fn sorted_background_highlights_in_range(
20482        &self,
20483        search_range: Range<Anchor>,
20484        display_snapshot: &DisplaySnapshot,
20485        theme: &Theme,
20486    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20487        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20488        res.sort_by(|a, b| {
20489            a.0.start
20490                .cmp(&b.0.start)
20491                .then_with(|| a.0.end.cmp(&b.0.end))
20492                .then_with(|| a.1.cmp(&b.1))
20493        });
20494        res
20495    }
20496
20497    #[cfg(feature = "test-support")]
20498    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20499        let snapshot = self.buffer().read(cx).snapshot(cx);
20500
20501        let highlights = self
20502            .background_highlights
20503            .get(&HighlightKey::Type(TypeId::of::<
20504                items::BufferSearchHighlights,
20505            >()));
20506
20507        if let Some((_color, ranges)) = highlights {
20508            ranges
20509                .iter()
20510                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20511                .collect_vec()
20512        } else {
20513            vec![]
20514        }
20515    }
20516
20517    fn document_highlights_for_position<'a>(
20518        &'a self,
20519        position: Anchor,
20520        buffer: &'a MultiBufferSnapshot,
20521    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20522        let read_highlights = self
20523            .background_highlights
20524            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20525            .map(|h| &h.1);
20526        let write_highlights = self
20527            .background_highlights
20528            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20529            .map(|h| &h.1);
20530        let left_position = position.bias_left(buffer);
20531        let right_position = position.bias_right(buffer);
20532        read_highlights
20533            .into_iter()
20534            .chain(write_highlights)
20535            .flat_map(move |ranges| {
20536                let start_ix = match ranges.binary_search_by(|probe| {
20537                    let cmp = probe.end.cmp(&left_position, buffer);
20538                    if cmp.is_ge() {
20539                        Ordering::Greater
20540                    } else {
20541                        Ordering::Less
20542                    }
20543                }) {
20544                    Ok(i) | Err(i) => i,
20545                };
20546
20547                ranges[start_ix..]
20548                    .iter()
20549                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20550            })
20551    }
20552
20553    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20554        self.background_highlights
20555            .get(&HighlightKey::Type(TypeId::of::<T>()))
20556            .is_some_and(|(_, highlights)| !highlights.is_empty())
20557    }
20558
20559    /// Returns all background highlights for a given range.
20560    ///
20561    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20562    pub fn background_highlights_in_range(
20563        &self,
20564        search_range: Range<Anchor>,
20565        display_snapshot: &DisplaySnapshot,
20566        theme: &Theme,
20567    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20568        let mut results = Vec::new();
20569        for (color_fetcher, ranges) in self.background_highlights.values() {
20570            let color = color_fetcher(theme);
20571            let start_ix = match ranges.binary_search_by(|probe| {
20572                let cmp = probe
20573                    .end
20574                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20575                if cmp.is_gt() {
20576                    Ordering::Greater
20577                } else {
20578                    Ordering::Less
20579                }
20580            }) {
20581                Ok(i) | Err(i) => i,
20582            };
20583            for range in &ranges[start_ix..] {
20584                if range
20585                    .start
20586                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20587                    .is_ge()
20588                {
20589                    break;
20590                }
20591
20592                let start = range.start.to_display_point(display_snapshot);
20593                let end = range.end.to_display_point(display_snapshot);
20594                results.push((start..end, color))
20595            }
20596        }
20597        results
20598    }
20599
20600    pub fn gutter_highlights_in_range(
20601        &self,
20602        search_range: Range<Anchor>,
20603        display_snapshot: &DisplaySnapshot,
20604        cx: &App,
20605    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20606        let mut results = Vec::new();
20607        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20608            let color = color_fetcher(cx);
20609            let start_ix = match ranges.binary_search_by(|probe| {
20610                let cmp = probe
20611                    .end
20612                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20613                if cmp.is_gt() {
20614                    Ordering::Greater
20615                } else {
20616                    Ordering::Less
20617                }
20618            }) {
20619                Ok(i) | Err(i) => i,
20620            };
20621            for range in &ranges[start_ix..] {
20622                if range
20623                    .start
20624                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20625                    .is_ge()
20626                {
20627                    break;
20628                }
20629
20630                let start = range.start.to_display_point(display_snapshot);
20631                let end = range.end.to_display_point(display_snapshot);
20632                results.push((start..end, color))
20633            }
20634        }
20635        results
20636    }
20637
20638    /// Get the text ranges corresponding to the redaction query
20639    pub fn redacted_ranges(
20640        &self,
20641        search_range: Range<Anchor>,
20642        display_snapshot: &DisplaySnapshot,
20643        cx: &App,
20644    ) -> Vec<Range<DisplayPoint>> {
20645        display_snapshot
20646            .buffer_snapshot()
20647            .redacted_ranges(search_range, |file| {
20648                if let Some(file) = file {
20649                    file.is_private()
20650                        && EditorSettings::get(
20651                            Some(SettingsLocation {
20652                                worktree_id: file.worktree_id(cx),
20653                                path: file.path().as_ref(),
20654                            }),
20655                            cx,
20656                        )
20657                        .redact_private_values
20658                } else {
20659                    false
20660                }
20661            })
20662            .map(|range| {
20663                range.start.to_display_point(display_snapshot)
20664                    ..range.end.to_display_point(display_snapshot)
20665            })
20666            .collect()
20667    }
20668
20669    pub fn highlight_text_key<T: 'static>(
20670        &mut self,
20671        key: usize,
20672        ranges: Vec<Range<Anchor>>,
20673        style: HighlightStyle,
20674        cx: &mut Context<Self>,
20675    ) {
20676        self.display_map.update(cx, |map, _| {
20677            map.highlight_text(
20678                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20679                ranges,
20680                style,
20681            );
20682        });
20683        cx.notify();
20684    }
20685
20686    pub fn highlight_text<T: 'static>(
20687        &mut self,
20688        ranges: Vec<Range<Anchor>>,
20689        style: HighlightStyle,
20690        cx: &mut Context<Self>,
20691    ) {
20692        self.display_map.update(cx, |map, _| {
20693            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20694        });
20695        cx.notify();
20696    }
20697
20698    pub(crate) fn highlight_inlays<T: 'static>(
20699        &mut self,
20700        highlights: Vec<InlayHighlight>,
20701        style: HighlightStyle,
20702        cx: &mut Context<Self>,
20703    ) {
20704        self.display_map.update(cx, |map, _| {
20705            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20706        });
20707        cx.notify();
20708    }
20709
20710    pub fn text_highlights<'a, T: 'static>(
20711        &'a self,
20712        cx: &'a App,
20713    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20714        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20715    }
20716
20717    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20718        let cleared = self
20719            .display_map
20720            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20721        if cleared {
20722            cx.notify();
20723        }
20724    }
20725
20726    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20727        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20728            && self.focus_handle.is_focused(window)
20729    }
20730
20731    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20732        self.show_cursor_when_unfocused = is_enabled;
20733        cx.notify();
20734    }
20735
20736    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20737        cx.notify();
20738    }
20739
20740    fn on_debug_session_event(
20741        &mut self,
20742        _session: Entity<Session>,
20743        event: &SessionEvent,
20744        cx: &mut Context<Self>,
20745    ) {
20746        if let SessionEvent::InvalidateInlineValue = event {
20747            self.refresh_inline_values(cx);
20748        }
20749    }
20750
20751    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20752        let Some(project) = self.project.clone() else {
20753            return;
20754        };
20755
20756        if !self.inline_value_cache.enabled {
20757            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20758            self.splice_inlays(&inlays, Vec::new(), cx);
20759            return;
20760        }
20761
20762        let current_execution_position = self
20763            .highlighted_rows
20764            .get(&TypeId::of::<ActiveDebugLine>())
20765            .and_then(|lines| lines.last().map(|line| line.range.end));
20766
20767        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20768            let inline_values = editor
20769                .update(cx, |editor, cx| {
20770                    let Some(current_execution_position) = current_execution_position else {
20771                        return Some(Task::ready(Ok(Vec::new())));
20772                    };
20773
20774                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20775                        let snapshot = buffer.snapshot(cx);
20776
20777                        let excerpt = snapshot.excerpt_containing(
20778                            current_execution_position..current_execution_position,
20779                        )?;
20780
20781                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20782                    })?;
20783
20784                    let range =
20785                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20786
20787                    project.inline_values(buffer, range, cx)
20788                })
20789                .ok()
20790                .flatten()?
20791                .await
20792                .context("refreshing debugger inlays")
20793                .log_err()?;
20794
20795            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20796
20797            for (buffer_id, inline_value) in inline_values
20798                .into_iter()
20799                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20800            {
20801                buffer_inline_values
20802                    .entry(buffer_id)
20803                    .or_default()
20804                    .push(inline_value);
20805            }
20806
20807            editor
20808                .update(cx, |editor, cx| {
20809                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20810                    let mut new_inlays = Vec::default();
20811
20812                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20813                        let buffer_id = buffer_snapshot.remote_id();
20814                        buffer_inline_values
20815                            .get(&buffer_id)
20816                            .into_iter()
20817                            .flatten()
20818                            .for_each(|hint| {
20819                                let inlay = Inlay::debugger(
20820                                    post_inc(&mut editor.next_inlay_id),
20821                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20822                                    hint.text(),
20823                                );
20824                                if !inlay.text().chars().contains(&'\n') {
20825                                    new_inlays.push(inlay);
20826                                }
20827                            });
20828                    }
20829
20830                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20831                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20832
20833                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20834                })
20835                .ok()?;
20836            Some(())
20837        });
20838    }
20839
20840    fn on_buffer_event(
20841        &mut self,
20842        multibuffer: &Entity<MultiBuffer>,
20843        event: &multi_buffer::Event,
20844        window: &mut Window,
20845        cx: &mut Context<Self>,
20846    ) {
20847        match event {
20848            multi_buffer::Event::Edited { edited_buffer } => {
20849                self.scrollbar_marker_state.dirty = true;
20850                self.active_indent_guides_state.dirty = true;
20851                self.refresh_active_diagnostics(cx);
20852                self.refresh_code_actions(window, cx);
20853                self.refresh_selected_text_highlights(true, window, cx);
20854                self.refresh_single_line_folds(window, cx);
20855                refresh_matching_bracket_highlights(self, cx);
20856                if self.has_active_edit_prediction() {
20857                    self.update_visible_edit_prediction(window, cx);
20858                }
20859
20860                if let Some(edited_buffer) = edited_buffer {
20861                    if edited_buffer.read(cx).file().is_none() {
20862                        cx.emit(EditorEvent::TitleChanged);
20863                    }
20864
20865                    let buffer_id = edited_buffer.read(cx).remote_id();
20866                    if let Some(project) = self.project.clone() {
20867                        self.register_buffer(buffer_id, cx);
20868                        self.update_lsp_data(Some(buffer_id), window, cx);
20869                        #[allow(clippy::mutable_key_type)]
20870                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20871                            multibuffer
20872                                .all_buffers()
20873                                .into_iter()
20874                                .filter_map(|buffer| {
20875                                    buffer.update(cx, |buffer, cx| {
20876                                        let language = buffer.language()?;
20877                                        let should_discard = project.update(cx, |project, cx| {
20878                                            project.is_local()
20879                                                && !project.has_language_servers_for(buffer, cx)
20880                                        });
20881                                        should_discard.not().then_some(language.clone())
20882                                    })
20883                                })
20884                                .collect::<HashSet<_>>()
20885                        });
20886                        if !languages_affected.is_empty() {
20887                            self.refresh_inlay_hints(
20888                                InlayHintRefreshReason::BufferEdited(languages_affected),
20889                                cx,
20890                            );
20891                        }
20892                    }
20893                }
20894
20895                cx.emit(EditorEvent::BufferEdited);
20896                cx.emit(SearchEvent::MatchesInvalidated);
20897
20898                let Some(project) = &self.project else { return };
20899                let (telemetry, is_via_ssh) = {
20900                    let project = project.read(cx);
20901                    let telemetry = project.client().telemetry().clone();
20902                    let is_via_ssh = project.is_via_remote_server();
20903                    (telemetry, is_via_ssh)
20904                };
20905                telemetry.log_edit_event("editor", is_via_ssh);
20906            }
20907            multi_buffer::Event::ExcerptsAdded {
20908                buffer,
20909                predecessor,
20910                excerpts,
20911            } => {
20912                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20913                let buffer_id = buffer.read(cx).remote_id();
20914                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20915                    && let Some(project) = &self.project
20916                {
20917                    update_uncommitted_diff_for_buffer(
20918                        cx.entity(),
20919                        project,
20920                        [buffer.clone()],
20921                        self.buffer.clone(),
20922                        cx,
20923                    )
20924                    .detach();
20925                }
20926                self.update_lsp_data(Some(buffer_id), window, cx);
20927                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20928                cx.emit(EditorEvent::ExcerptsAdded {
20929                    buffer: buffer.clone(),
20930                    predecessor: *predecessor,
20931                    excerpts: excerpts.clone(),
20932                });
20933            }
20934            multi_buffer::Event::ExcerptsRemoved {
20935                ids,
20936                removed_buffer_ids,
20937            } => {
20938                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20939                for buffer_id in removed_buffer_ids {
20940                    self.registered_buffers.remove(buffer_id);
20941                }
20942                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20943                cx.emit(EditorEvent::ExcerptsRemoved {
20944                    ids: ids.clone(),
20945                    removed_buffer_ids: removed_buffer_ids.clone(),
20946                });
20947            }
20948            multi_buffer::Event::ExcerptsEdited {
20949                excerpt_ids,
20950                buffer_ids,
20951            } => {
20952                self.display_map.update(cx, |map, cx| {
20953                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20954                });
20955                cx.emit(EditorEvent::ExcerptsEdited {
20956                    ids: excerpt_ids.clone(),
20957                });
20958            }
20959            multi_buffer::Event::ExcerptsExpanded { ids } => {
20960                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20961                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20962            }
20963            multi_buffer::Event::Reparsed(buffer_id) => {
20964                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20965                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20966
20967                cx.emit(EditorEvent::Reparsed(*buffer_id));
20968            }
20969            multi_buffer::Event::DiffHunksToggled => {
20970                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20971            }
20972            multi_buffer::Event::LanguageChanged(buffer_id) => {
20973                self.registered_buffers.remove(&buffer_id);
20974                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20975                cx.emit(EditorEvent::Reparsed(*buffer_id));
20976                cx.notify();
20977            }
20978            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20979            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20980            multi_buffer::Event::FileHandleChanged
20981            | multi_buffer::Event::Reloaded
20982            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20983            multi_buffer::Event::DiagnosticsUpdated => {
20984                self.update_diagnostics_state(window, cx);
20985            }
20986            _ => {}
20987        };
20988    }
20989
20990    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20991        if !self.diagnostics_enabled() {
20992            return;
20993        }
20994        self.refresh_active_diagnostics(cx);
20995        self.refresh_inline_diagnostics(true, window, cx);
20996        self.scrollbar_marker_state.dirty = true;
20997        cx.notify();
20998    }
20999
21000    pub fn start_temporary_diff_override(&mut self) {
21001        self.load_diff_task.take();
21002        self.temporary_diff_override = true;
21003    }
21004
21005    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21006        self.temporary_diff_override = false;
21007        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21008        self.buffer.update(cx, |buffer, cx| {
21009            buffer.set_all_diff_hunks_collapsed(cx);
21010        });
21011
21012        if let Some(project) = self.project.clone() {
21013            self.load_diff_task = Some(
21014                update_uncommitted_diff_for_buffer(
21015                    cx.entity(),
21016                    &project,
21017                    self.buffer.read(cx).all_buffers(),
21018                    self.buffer.clone(),
21019                    cx,
21020                )
21021                .shared(),
21022            );
21023        }
21024    }
21025
21026    fn on_display_map_changed(
21027        &mut self,
21028        _: Entity<DisplayMap>,
21029        _: &mut Window,
21030        cx: &mut Context<Self>,
21031    ) {
21032        cx.notify();
21033    }
21034
21035    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21036        if self.diagnostics_enabled() {
21037            let new_severity = EditorSettings::get_global(cx)
21038                .diagnostics_max_severity
21039                .unwrap_or(DiagnosticSeverity::Hint);
21040            self.set_max_diagnostics_severity(new_severity, cx);
21041        }
21042        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21043        self.update_edit_prediction_settings(cx);
21044        self.refresh_edit_prediction(true, false, window, cx);
21045        self.refresh_inline_values(cx);
21046        self.refresh_inlay_hints(
21047            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21048                self.selections.newest_anchor().head(),
21049                &self.buffer.read(cx).snapshot(cx),
21050                cx,
21051            )),
21052            cx,
21053        );
21054
21055        let old_cursor_shape = self.cursor_shape;
21056        let old_show_breadcrumbs = self.show_breadcrumbs;
21057
21058        {
21059            let editor_settings = EditorSettings::get_global(cx);
21060            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21061            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21062            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21063            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21064        }
21065
21066        if old_cursor_shape != self.cursor_shape {
21067            cx.emit(EditorEvent::CursorShapeChanged);
21068        }
21069
21070        if old_show_breadcrumbs != self.show_breadcrumbs {
21071            cx.emit(EditorEvent::BreadcrumbsChanged);
21072        }
21073
21074        let project_settings = ProjectSettings::get_global(cx);
21075        self.serialize_dirty_buffers =
21076            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21077
21078        if self.mode.is_full() {
21079            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21080            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21081            if self.show_inline_diagnostics != show_inline_diagnostics {
21082                self.show_inline_diagnostics = show_inline_diagnostics;
21083                self.refresh_inline_diagnostics(false, window, cx);
21084            }
21085
21086            if self.git_blame_inline_enabled != inline_blame_enabled {
21087                self.toggle_git_blame_inline_internal(false, window, cx);
21088            }
21089
21090            let minimap_settings = EditorSettings::get_global(cx).minimap;
21091            if self.minimap_visibility != MinimapVisibility::Disabled {
21092                if self.minimap_visibility.settings_visibility()
21093                    != minimap_settings.minimap_enabled()
21094                {
21095                    self.set_minimap_visibility(
21096                        MinimapVisibility::for_mode(self.mode(), cx),
21097                        window,
21098                        cx,
21099                    );
21100                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21101                    minimap_entity.update(cx, |minimap_editor, cx| {
21102                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21103                    })
21104                }
21105            }
21106        }
21107
21108        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21109            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21110        }) {
21111            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21112                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21113            }
21114            self.refresh_colors_for_visible_range(None, window, cx);
21115        }
21116
21117        cx.notify();
21118    }
21119
21120    pub fn set_searchable(&mut self, searchable: bool) {
21121        self.searchable = searchable;
21122    }
21123
21124    pub fn searchable(&self) -> bool {
21125        self.searchable
21126    }
21127
21128    fn open_proposed_changes_editor(
21129        &mut self,
21130        _: &OpenProposedChangesEditor,
21131        window: &mut Window,
21132        cx: &mut Context<Self>,
21133    ) {
21134        let Some(workspace) = self.workspace() else {
21135            cx.propagate();
21136            return;
21137        };
21138
21139        let selections = self.selections.all::<usize>(cx);
21140        let multi_buffer = self.buffer.read(cx);
21141        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21142        let mut new_selections_by_buffer = HashMap::default();
21143        for selection in selections {
21144            for (buffer, range, _) in
21145                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21146            {
21147                let mut range = range.to_point(buffer);
21148                range.start.column = 0;
21149                range.end.column = buffer.line_len(range.end.row);
21150                new_selections_by_buffer
21151                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21152                    .or_insert(Vec::new())
21153                    .push(range)
21154            }
21155        }
21156
21157        let proposed_changes_buffers = new_selections_by_buffer
21158            .into_iter()
21159            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21160            .collect::<Vec<_>>();
21161        let proposed_changes_editor = cx.new(|cx| {
21162            ProposedChangesEditor::new(
21163                "Proposed changes",
21164                proposed_changes_buffers,
21165                self.project.clone(),
21166                window,
21167                cx,
21168            )
21169        });
21170
21171        window.defer(cx, move |window, cx| {
21172            workspace.update(cx, |workspace, cx| {
21173                workspace.active_pane().update(cx, |pane, cx| {
21174                    pane.add_item(
21175                        Box::new(proposed_changes_editor),
21176                        true,
21177                        true,
21178                        None,
21179                        window,
21180                        cx,
21181                    );
21182                });
21183            });
21184        });
21185    }
21186
21187    pub fn open_excerpts_in_split(
21188        &mut self,
21189        _: &OpenExcerptsSplit,
21190        window: &mut Window,
21191        cx: &mut Context<Self>,
21192    ) {
21193        self.open_excerpts_common(None, true, window, cx)
21194    }
21195
21196    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21197        self.open_excerpts_common(None, false, window, cx)
21198    }
21199
21200    fn open_excerpts_common(
21201        &mut self,
21202        jump_data: Option<JumpData>,
21203        split: bool,
21204        window: &mut Window,
21205        cx: &mut Context<Self>,
21206    ) {
21207        let Some(workspace) = self.workspace() else {
21208            cx.propagate();
21209            return;
21210        };
21211
21212        if self.buffer.read(cx).is_singleton() {
21213            cx.propagate();
21214            return;
21215        }
21216
21217        let mut new_selections_by_buffer = HashMap::default();
21218        match &jump_data {
21219            Some(JumpData::MultiBufferPoint {
21220                excerpt_id,
21221                position,
21222                anchor,
21223                line_offset_from_top,
21224            }) => {
21225                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21226                if let Some(buffer) = multi_buffer_snapshot
21227                    .buffer_id_for_excerpt(*excerpt_id)
21228                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21229                {
21230                    let buffer_snapshot = buffer.read(cx).snapshot();
21231                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21232                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21233                    } else {
21234                        buffer_snapshot.clip_point(*position, Bias::Left)
21235                    };
21236                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21237                    new_selections_by_buffer.insert(
21238                        buffer,
21239                        (
21240                            vec![jump_to_offset..jump_to_offset],
21241                            Some(*line_offset_from_top),
21242                        ),
21243                    );
21244                }
21245            }
21246            Some(JumpData::MultiBufferRow {
21247                row,
21248                line_offset_from_top,
21249            }) => {
21250                let point = MultiBufferPoint::new(row.0, 0);
21251                if let Some((buffer, buffer_point, _)) =
21252                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21253                {
21254                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21255                    new_selections_by_buffer
21256                        .entry(buffer)
21257                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21258                        .0
21259                        .push(buffer_offset..buffer_offset)
21260                }
21261            }
21262            None => {
21263                let selections = self.selections.all::<usize>(cx);
21264                let multi_buffer = self.buffer.read(cx);
21265                for selection in selections {
21266                    for (snapshot, range, _, anchor) in multi_buffer
21267                        .snapshot(cx)
21268                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21269                    {
21270                        if let Some(anchor) = anchor {
21271                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21272                            else {
21273                                continue;
21274                            };
21275                            let offset = text::ToOffset::to_offset(
21276                                &anchor.text_anchor,
21277                                &buffer_handle.read(cx).snapshot(),
21278                            );
21279                            let range = offset..offset;
21280                            new_selections_by_buffer
21281                                .entry(buffer_handle)
21282                                .or_insert((Vec::new(), None))
21283                                .0
21284                                .push(range)
21285                        } else {
21286                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21287                            else {
21288                                continue;
21289                            };
21290                            new_selections_by_buffer
21291                                .entry(buffer_handle)
21292                                .or_insert((Vec::new(), None))
21293                                .0
21294                                .push(range)
21295                        }
21296                    }
21297                }
21298            }
21299        }
21300
21301        new_selections_by_buffer
21302            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21303
21304        if new_selections_by_buffer.is_empty() {
21305            return;
21306        }
21307
21308        // We defer the pane interaction because we ourselves are a workspace item
21309        // and activating a new item causes the pane to call a method on us reentrantly,
21310        // which panics if we're on the stack.
21311        window.defer(cx, move |window, cx| {
21312            workspace.update(cx, |workspace, cx| {
21313                let pane = if split {
21314                    workspace.adjacent_pane(window, cx)
21315                } else {
21316                    workspace.active_pane().clone()
21317                };
21318
21319                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21320                    let editor = buffer
21321                        .read(cx)
21322                        .file()
21323                        .is_none()
21324                        .then(|| {
21325                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21326                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21327                            // Instead, we try to activate the existing editor in the pane first.
21328                            let (editor, pane_item_index) =
21329                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21330                                    let editor = item.downcast::<Editor>()?;
21331                                    let singleton_buffer =
21332                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21333                                    if singleton_buffer == buffer {
21334                                        Some((editor, i))
21335                                    } else {
21336                                        None
21337                                    }
21338                                })?;
21339                            pane.update(cx, |pane, cx| {
21340                                pane.activate_item(pane_item_index, true, true, window, cx)
21341                            });
21342                            Some(editor)
21343                        })
21344                        .flatten()
21345                        .unwrap_or_else(|| {
21346                            workspace.open_project_item::<Self>(
21347                                pane.clone(),
21348                                buffer,
21349                                true,
21350                                true,
21351                                window,
21352                                cx,
21353                            )
21354                        });
21355
21356                    editor.update(cx, |editor, cx| {
21357                        let autoscroll = match scroll_offset {
21358                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21359                            None => Autoscroll::newest(),
21360                        };
21361                        let nav_history = editor.nav_history.take();
21362                        editor.change_selections(
21363                            SelectionEffects::scroll(autoscroll),
21364                            window,
21365                            cx,
21366                            |s| {
21367                                s.select_ranges(ranges);
21368                            },
21369                        );
21370                        editor.nav_history = nav_history;
21371                    });
21372                }
21373            })
21374        });
21375    }
21376
21377    // For now, don't allow opening excerpts in buffers that aren't backed by
21378    // regular project files.
21379    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21380        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21381    }
21382
21383    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21384        let snapshot = self.buffer.read(cx).read(cx);
21385        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21386        Some(
21387            ranges
21388                .iter()
21389                .map(move |range| {
21390                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21391                })
21392                .collect(),
21393        )
21394    }
21395
21396    fn selection_replacement_ranges(
21397        &self,
21398        range: Range<OffsetUtf16>,
21399        cx: &mut App,
21400    ) -> Vec<Range<OffsetUtf16>> {
21401        let selections = self.selections.all::<OffsetUtf16>(cx);
21402        let newest_selection = selections
21403            .iter()
21404            .max_by_key(|selection| selection.id)
21405            .unwrap();
21406        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21407        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21408        let snapshot = self.buffer.read(cx).read(cx);
21409        selections
21410            .into_iter()
21411            .map(|mut selection| {
21412                selection.start.0 =
21413                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21414                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21415                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21416                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21417            })
21418            .collect()
21419    }
21420
21421    fn report_editor_event(
21422        &self,
21423        reported_event: ReportEditorEvent,
21424        file_extension: Option<String>,
21425        cx: &App,
21426    ) {
21427        if cfg!(any(test, feature = "test-support")) {
21428            return;
21429        }
21430
21431        let Some(project) = &self.project else { return };
21432
21433        // If None, we are in a file without an extension
21434        let file = self
21435            .buffer
21436            .read(cx)
21437            .as_singleton()
21438            .and_then(|b| b.read(cx).file());
21439        let file_extension = file_extension.or(file
21440            .as_ref()
21441            .and_then(|file| Path::new(file.file_name(cx)).extension())
21442            .and_then(|e| e.to_str())
21443            .map(|a| a.to_string()));
21444
21445        let vim_mode = vim_enabled(cx);
21446
21447        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21448        let copilot_enabled = edit_predictions_provider
21449            == language::language_settings::EditPredictionProvider::Copilot;
21450        let copilot_enabled_for_language = self
21451            .buffer
21452            .read(cx)
21453            .language_settings(cx)
21454            .show_edit_predictions;
21455
21456        let project = project.read(cx);
21457        let event_type = reported_event.event_type();
21458
21459        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21460            telemetry::event!(
21461                event_type,
21462                type = if auto_saved {"autosave"} else {"manual"},
21463                file_extension,
21464                vim_mode,
21465                copilot_enabled,
21466                copilot_enabled_for_language,
21467                edit_predictions_provider,
21468                is_via_ssh = project.is_via_remote_server(),
21469            );
21470        } else {
21471            telemetry::event!(
21472                event_type,
21473                file_extension,
21474                vim_mode,
21475                copilot_enabled,
21476                copilot_enabled_for_language,
21477                edit_predictions_provider,
21478                is_via_ssh = project.is_via_remote_server(),
21479            );
21480        };
21481    }
21482
21483    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21484    /// with each line being an array of {text, highlight} objects.
21485    fn copy_highlight_json(
21486        &mut self,
21487        _: &CopyHighlightJson,
21488        window: &mut Window,
21489        cx: &mut Context<Self>,
21490    ) {
21491        #[derive(Serialize)]
21492        struct Chunk<'a> {
21493            text: String,
21494            highlight: Option<&'a str>,
21495        }
21496
21497        let snapshot = self.buffer.read(cx).snapshot(cx);
21498        let range = self
21499            .selected_text_range(false, window, cx)
21500            .and_then(|selection| {
21501                if selection.range.is_empty() {
21502                    None
21503                } else {
21504                    Some(selection.range)
21505                }
21506            })
21507            .unwrap_or_else(|| 0..snapshot.len());
21508
21509        let chunks = snapshot.chunks(range, true);
21510        let mut lines = Vec::new();
21511        let mut line: VecDeque<Chunk> = VecDeque::new();
21512
21513        let Some(style) = self.style.as_ref() else {
21514            return;
21515        };
21516
21517        for chunk in chunks {
21518            let highlight = chunk
21519                .syntax_highlight_id
21520                .and_then(|id| id.name(&style.syntax));
21521            let mut chunk_lines = chunk.text.split('\n').peekable();
21522            while let Some(text) = chunk_lines.next() {
21523                let mut merged_with_last_token = false;
21524                if let Some(last_token) = line.back_mut()
21525                    && last_token.highlight == highlight
21526                {
21527                    last_token.text.push_str(text);
21528                    merged_with_last_token = true;
21529                }
21530
21531                if !merged_with_last_token {
21532                    line.push_back(Chunk {
21533                        text: text.into(),
21534                        highlight,
21535                    });
21536                }
21537
21538                if chunk_lines.peek().is_some() {
21539                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21540                        line.pop_front();
21541                    }
21542                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21543                        line.pop_back();
21544                    }
21545
21546                    lines.push(mem::take(&mut line));
21547                }
21548            }
21549        }
21550
21551        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21552            return;
21553        };
21554        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21555    }
21556
21557    pub fn open_context_menu(
21558        &mut self,
21559        _: &OpenContextMenu,
21560        window: &mut Window,
21561        cx: &mut Context<Self>,
21562    ) {
21563        self.request_autoscroll(Autoscroll::newest(), cx);
21564        let position = self.selections.newest_display(cx).start;
21565        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21566    }
21567
21568    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21569        &self.inlay_hint_cache
21570    }
21571
21572    pub fn replay_insert_event(
21573        &mut self,
21574        text: &str,
21575        relative_utf16_range: Option<Range<isize>>,
21576        window: &mut Window,
21577        cx: &mut Context<Self>,
21578    ) {
21579        if !self.input_enabled {
21580            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21581            return;
21582        }
21583        if let Some(relative_utf16_range) = relative_utf16_range {
21584            let selections = self.selections.all::<OffsetUtf16>(cx);
21585            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21586                let new_ranges = selections.into_iter().map(|range| {
21587                    let start = OffsetUtf16(
21588                        range
21589                            .head()
21590                            .0
21591                            .saturating_add_signed(relative_utf16_range.start),
21592                    );
21593                    let end = OffsetUtf16(
21594                        range
21595                            .head()
21596                            .0
21597                            .saturating_add_signed(relative_utf16_range.end),
21598                    );
21599                    start..end
21600                });
21601                s.select_ranges(new_ranges);
21602            });
21603        }
21604
21605        self.handle_input(text, window, cx);
21606    }
21607
21608    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21609        let Some(provider) = self.semantics_provider.as_ref() else {
21610            return false;
21611        };
21612
21613        let mut supports = false;
21614        self.buffer().update(cx, |this, cx| {
21615            this.for_each_buffer(|buffer| {
21616                supports |= provider.supports_inlay_hints(buffer, cx);
21617            });
21618        });
21619
21620        supports
21621    }
21622
21623    pub fn is_focused(&self, window: &Window) -> bool {
21624        self.focus_handle.is_focused(window)
21625    }
21626
21627    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21628        cx.emit(EditorEvent::Focused);
21629
21630        if let Some(descendant) = self
21631            .last_focused_descendant
21632            .take()
21633            .and_then(|descendant| descendant.upgrade())
21634        {
21635            window.focus(&descendant);
21636        } else {
21637            if let Some(blame) = self.blame.as_ref() {
21638                blame.update(cx, GitBlame::focus)
21639            }
21640
21641            self.blink_manager.update(cx, BlinkManager::enable);
21642            self.show_cursor_names(window, cx);
21643            self.buffer.update(cx, |buffer, cx| {
21644                buffer.finalize_last_transaction(cx);
21645                if self.leader_id.is_none() {
21646                    buffer.set_active_selections(
21647                        &self.selections.disjoint_anchors_arc(),
21648                        self.selections.line_mode(),
21649                        self.cursor_shape,
21650                        cx,
21651                    );
21652                }
21653            });
21654        }
21655    }
21656
21657    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21658        cx.emit(EditorEvent::FocusedIn)
21659    }
21660
21661    fn handle_focus_out(
21662        &mut self,
21663        event: FocusOutEvent,
21664        _window: &mut Window,
21665        cx: &mut Context<Self>,
21666    ) {
21667        if event.blurred != self.focus_handle {
21668            self.last_focused_descendant = Some(event.blurred);
21669        }
21670        self.selection_drag_state = SelectionDragState::None;
21671        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21672    }
21673
21674    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21675        self.blink_manager.update(cx, BlinkManager::disable);
21676        self.buffer
21677            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21678
21679        if let Some(blame) = self.blame.as_ref() {
21680            blame.update(cx, GitBlame::blur)
21681        }
21682        if !self.hover_state.focused(window, cx) {
21683            hide_hover(self, cx);
21684        }
21685        if !self
21686            .context_menu
21687            .borrow()
21688            .as_ref()
21689            .is_some_and(|context_menu| context_menu.focused(window, cx))
21690        {
21691            self.hide_context_menu(window, cx);
21692        }
21693        self.take_active_edit_prediction(cx);
21694        cx.emit(EditorEvent::Blurred);
21695        cx.notify();
21696    }
21697
21698    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21699        let mut pending: String = window
21700            .pending_input_keystrokes()
21701            .into_iter()
21702            .flatten()
21703            .filter_map(|keystroke| {
21704                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21705                    keystroke.key_char.clone()
21706                } else {
21707                    None
21708                }
21709            })
21710            .collect();
21711
21712        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21713            pending = "".to_string();
21714        }
21715
21716        let existing_pending = self
21717            .text_highlights::<PendingInput>(cx)
21718            .map(|(_, ranges)| ranges.to_vec());
21719        if existing_pending.is_none() && pending.is_empty() {
21720            return;
21721        }
21722        let transaction =
21723            self.transact(window, cx, |this, window, cx| {
21724                let selections = this.selections.all::<usize>(cx);
21725                let edits = selections
21726                    .iter()
21727                    .map(|selection| (selection.end..selection.end, pending.clone()));
21728                this.edit(edits, cx);
21729                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21730                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21731                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21732                    }));
21733                });
21734                if let Some(existing_ranges) = existing_pending {
21735                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21736                    this.edit(edits, cx);
21737                }
21738            });
21739
21740        let snapshot = self.snapshot(window, cx);
21741        let ranges = self
21742            .selections
21743            .all::<usize>(cx)
21744            .into_iter()
21745            .map(|selection| {
21746                snapshot.buffer_snapshot().anchor_after(selection.end)
21747                    ..snapshot
21748                        .buffer_snapshot()
21749                        .anchor_before(selection.end + pending.len())
21750            })
21751            .collect();
21752
21753        if pending.is_empty() {
21754            self.clear_highlights::<PendingInput>(cx);
21755        } else {
21756            self.highlight_text::<PendingInput>(
21757                ranges,
21758                HighlightStyle {
21759                    underline: Some(UnderlineStyle {
21760                        thickness: px(1.),
21761                        color: None,
21762                        wavy: false,
21763                    }),
21764                    ..Default::default()
21765                },
21766                cx,
21767            );
21768        }
21769
21770        self.ime_transaction = self.ime_transaction.or(transaction);
21771        if let Some(transaction) = self.ime_transaction {
21772            self.buffer.update(cx, |buffer, cx| {
21773                buffer.group_until_transaction(transaction, cx);
21774            });
21775        }
21776
21777        if self.text_highlights::<PendingInput>(cx).is_none() {
21778            self.ime_transaction.take();
21779        }
21780    }
21781
21782    pub fn register_action_renderer(
21783        &mut self,
21784        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21785    ) -> Subscription {
21786        let id = self.next_editor_action_id.post_inc();
21787        self.editor_actions
21788            .borrow_mut()
21789            .insert(id, Box::new(listener));
21790
21791        let editor_actions = self.editor_actions.clone();
21792        Subscription::new(move || {
21793            editor_actions.borrow_mut().remove(&id);
21794        })
21795    }
21796
21797    pub fn register_action<A: Action>(
21798        &mut self,
21799        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21800    ) -> Subscription {
21801        let id = self.next_editor_action_id.post_inc();
21802        let listener = Arc::new(listener);
21803        self.editor_actions.borrow_mut().insert(
21804            id,
21805            Box::new(move |_, window, _| {
21806                let listener = listener.clone();
21807                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21808                    let action = action.downcast_ref().unwrap();
21809                    if phase == DispatchPhase::Bubble {
21810                        listener(action, window, cx)
21811                    }
21812                })
21813            }),
21814        );
21815
21816        let editor_actions = self.editor_actions.clone();
21817        Subscription::new(move || {
21818            editor_actions.borrow_mut().remove(&id);
21819        })
21820    }
21821
21822    pub fn file_header_size(&self) -> u32 {
21823        FILE_HEADER_HEIGHT
21824    }
21825
21826    pub fn restore(
21827        &mut self,
21828        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21829        window: &mut Window,
21830        cx: &mut Context<Self>,
21831    ) {
21832        let workspace = self.workspace();
21833        let project = self.project();
21834        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21835            let mut tasks = Vec::new();
21836            for (buffer_id, changes) in revert_changes {
21837                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21838                    buffer.update(cx, |buffer, cx| {
21839                        buffer.edit(
21840                            changes
21841                                .into_iter()
21842                                .map(|(range, text)| (range, text.to_string())),
21843                            None,
21844                            cx,
21845                        );
21846                    });
21847
21848                    if let Some(project) =
21849                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21850                    {
21851                        project.update(cx, |project, cx| {
21852                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21853                        })
21854                    }
21855                }
21856            }
21857            tasks
21858        });
21859        cx.spawn_in(window, async move |_, cx| {
21860            for (buffer, task) in save_tasks {
21861                let result = task.await;
21862                if result.is_err() {
21863                    let Some(path) = buffer
21864                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21865                        .ok()
21866                    else {
21867                        continue;
21868                    };
21869                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21870                        let Some(task) = cx
21871                            .update_window_entity(workspace, |workspace, window, cx| {
21872                                workspace
21873                                    .open_path_preview(path, None, false, false, false, window, cx)
21874                            })
21875                            .ok()
21876                        else {
21877                            continue;
21878                        };
21879                        task.await.log_err();
21880                    }
21881                }
21882            }
21883        })
21884        .detach();
21885        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21886            selections.refresh()
21887        });
21888    }
21889
21890    pub fn to_pixel_point(
21891        &self,
21892        source: multi_buffer::Anchor,
21893        editor_snapshot: &EditorSnapshot,
21894        window: &mut Window,
21895    ) -> Option<gpui::Point<Pixels>> {
21896        let source_point = source.to_display_point(editor_snapshot);
21897        self.display_to_pixel_point(source_point, editor_snapshot, window)
21898    }
21899
21900    pub fn display_to_pixel_point(
21901        &self,
21902        source: DisplayPoint,
21903        editor_snapshot: &EditorSnapshot,
21904        window: &mut Window,
21905    ) -> Option<gpui::Point<Pixels>> {
21906        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21907        let text_layout_details = self.text_layout_details(window);
21908        let scroll_top = text_layout_details
21909            .scroll_anchor
21910            .scroll_position(editor_snapshot)
21911            .y;
21912
21913        if source.row().as_f64() < scroll_top.floor() {
21914            return None;
21915        }
21916        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21917        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21918        Some(gpui::Point::new(source_x, source_y))
21919    }
21920
21921    pub fn has_visible_completions_menu(&self) -> bool {
21922        !self.edit_prediction_preview_is_active()
21923            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21924                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21925            })
21926    }
21927
21928    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21929        if self.mode.is_minimap() {
21930            return;
21931        }
21932        self.addons
21933            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21934    }
21935
21936    pub fn unregister_addon<T: Addon>(&mut self) {
21937        self.addons.remove(&std::any::TypeId::of::<T>());
21938    }
21939
21940    pub fn addon<T: Addon>(&self) -> Option<&T> {
21941        let type_id = std::any::TypeId::of::<T>();
21942        self.addons
21943            .get(&type_id)
21944            .and_then(|item| item.to_any().downcast_ref::<T>())
21945    }
21946
21947    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21948        let type_id = std::any::TypeId::of::<T>();
21949        self.addons
21950            .get_mut(&type_id)
21951            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21952    }
21953
21954    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21955        let text_layout_details = self.text_layout_details(window);
21956        let style = &text_layout_details.editor_style;
21957        let font_id = window.text_system().resolve_font(&style.text.font());
21958        let font_size = style.text.font_size.to_pixels(window.rem_size());
21959        let line_height = style.text.line_height_in_pixels(window.rem_size());
21960        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21961        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21962
21963        CharacterDimensions {
21964            em_width,
21965            em_advance,
21966            line_height,
21967        }
21968    }
21969
21970    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21971        self.load_diff_task.clone()
21972    }
21973
21974    fn read_metadata_from_db(
21975        &mut self,
21976        item_id: u64,
21977        workspace_id: WorkspaceId,
21978        window: &mut Window,
21979        cx: &mut Context<Editor>,
21980    ) {
21981        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21982            && !self.mode.is_minimap()
21983            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21984        {
21985            let buffer_snapshot = OnceCell::new();
21986
21987            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21988                && !folds.is_empty()
21989            {
21990                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21991                self.fold_ranges(
21992                    folds
21993                        .into_iter()
21994                        .map(|(start, end)| {
21995                            snapshot.clip_offset(start, Bias::Left)
21996                                ..snapshot.clip_offset(end, Bias::Right)
21997                        })
21998                        .collect(),
21999                    false,
22000                    window,
22001                    cx,
22002                );
22003            }
22004
22005            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22006                && !selections.is_empty()
22007            {
22008                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22009                // skip adding the initial selection to selection history
22010                self.selection_history.mode = SelectionHistoryMode::Skipping;
22011                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22012                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22013                        snapshot.clip_offset(start, Bias::Left)
22014                            ..snapshot.clip_offset(end, Bias::Right)
22015                    }));
22016                });
22017                self.selection_history.mode = SelectionHistoryMode::Normal;
22018            };
22019        }
22020
22021        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22022    }
22023
22024    fn update_lsp_data(
22025        &mut self,
22026        for_buffer: Option<BufferId>,
22027        window: &mut Window,
22028        cx: &mut Context<'_, Self>,
22029    ) {
22030        self.pull_diagnostics(for_buffer, window, cx);
22031        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22032    }
22033
22034    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22035        // Singletons are registered on editor creation.
22036        if self.ignore_lsp_data() || self.buffer().read(cx).is_singleton() {
22037            return;
22038        }
22039        for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
22040            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22041        }
22042    }
22043
22044    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
22045        if !self.registered_buffers.contains_key(&buffer_id)
22046            && let Some(project) = self.project.as_ref()
22047        {
22048            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22049                project.update(cx, |project, cx| {
22050                    self.registered_buffers.insert(
22051                        buffer_id,
22052                        project.register_buffer_with_language_servers(&buffer, cx),
22053                    );
22054                });
22055                return true;
22056            } else {
22057                self.registered_buffers.remove(&buffer_id);
22058            }
22059        }
22060
22061        false
22062    }
22063
22064    fn ignore_lsp_data(&self) -> bool {
22065        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22066        // skip any LSP updates for it.
22067        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22068    }
22069}
22070
22071fn edit_for_markdown_paste<'a>(
22072    buffer: &MultiBufferSnapshot,
22073    range: Range<usize>,
22074    to_insert: &'a str,
22075    url: Option<url::Url>,
22076) -> (Range<usize>, Cow<'a, str>) {
22077    if url.is_none() {
22078        return (range, Cow::Borrowed(to_insert));
22079    };
22080
22081    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22082
22083    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22084        Cow::Borrowed(to_insert)
22085    } else {
22086        Cow::Owned(format!("[{old_text}]({to_insert})"))
22087    };
22088    (range, new_text)
22089}
22090
22091fn vim_enabled(cx: &App) -> bool {
22092    vim_mode_setting::VimModeSetting::try_get(cx)
22093        .map(|vim_mode| vim_mode.0)
22094        .unwrap_or(false)
22095}
22096
22097fn process_completion_for_edit(
22098    completion: &Completion,
22099    intent: CompletionIntent,
22100    buffer: &Entity<Buffer>,
22101    cursor_position: &text::Anchor,
22102    cx: &mut Context<Editor>,
22103) -> CompletionEdit {
22104    let buffer = buffer.read(cx);
22105    let buffer_snapshot = buffer.snapshot();
22106    let (snippet, new_text) = if completion.is_snippet() {
22107        let mut snippet_source = completion.new_text.clone();
22108        // Workaround for typescript language server issues so that methods don't expand within
22109        // strings and functions with type expressions. The previous point is used because the query
22110        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22111        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22112        let previous_point = if previous_point.column > 0 {
22113            cursor_position.to_previous_offset(&buffer_snapshot)
22114        } else {
22115            cursor_position.to_offset(&buffer_snapshot)
22116        };
22117        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22118            && scope.prefers_label_for_snippet_in_completion()
22119            && let Some(label) = completion.label()
22120            && matches!(
22121                completion.kind(),
22122                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22123            )
22124        {
22125            snippet_source = label;
22126        }
22127        match Snippet::parse(&snippet_source).log_err() {
22128            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22129            None => (None, completion.new_text.clone()),
22130        }
22131    } else {
22132        (None, completion.new_text.clone())
22133    };
22134
22135    let mut range_to_replace = {
22136        let replace_range = &completion.replace_range;
22137        if let CompletionSource::Lsp {
22138            insert_range: Some(insert_range),
22139            ..
22140        } = &completion.source
22141        {
22142            debug_assert_eq!(
22143                insert_range.start, replace_range.start,
22144                "insert_range and replace_range should start at the same position"
22145            );
22146            debug_assert!(
22147                insert_range
22148                    .start
22149                    .cmp(cursor_position, &buffer_snapshot)
22150                    .is_le(),
22151                "insert_range should start before or at cursor position"
22152            );
22153            debug_assert!(
22154                replace_range
22155                    .start
22156                    .cmp(cursor_position, &buffer_snapshot)
22157                    .is_le(),
22158                "replace_range should start before or at cursor position"
22159            );
22160
22161            let should_replace = match intent {
22162                CompletionIntent::CompleteWithInsert => false,
22163                CompletionIntent::CompleteWithReplace => true,
22164                CompletionIntent::Complete | CompletionIntent::Compose => {
22165                    let insert_mode =
22166                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22167                            .completions
22168                            .lsp_insert_mode;
22169                    match insert_mode {
22170                        LspInsertMode::Insert => false,
22171                        LspInsertMode::Replace => true,
22172                        LspInsertMode::ReplaceSubsequence => {
22173                            let mut text_to_replace = buffer.chars_for_range(
22174                                buffer.anchor_before(replace_range.start)
22175                                    ..buffer.anchor_after(replace_range.end),
22176                            );
22177                            let mut current_needle = text_to_replace.next();
22178                            for haystack_ch in completion.label.text.chars() {
22179                                if let Some(needle_ch) = current_needle
22180                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22181                                {
22182                                    current_needle = text_to_replace.next();
22183                                }
22184                            }
22185                            current_needle.is_none()
22186                        }
22187                        LspInsertMode::ReplaceSuffix => {
22188                            if replace_range
22189                                .end
22190                                .cmp(cursor_position, &buffer_snapshot)
22191                                .is_gt()
22192                            {
22193                                let range_after_cursor = *cursor_position..replace_range.end;
22194                                let text_after_cursor = buffer
22195                                    .text_for_range(
22196                                        buffer.anchor_before(range_after_cursor.start)
22197                                            ..buffer.anchor_after(range_after_cursor.end),
22198                                    )
22199                                    .collect::<String>()
22200                                    .to_ascii_lowercase();
22201                                completion
22202                                    .label
22203                                    .text
22204                                    .to_ascii_lowercase()
22205                                    .ends_with(&text_after_cursor)
22206                            } else {
22207                                true
22208                            }
22209                        }
22210                    }
22211                }
22212            };
22213
22214            if should_replace {
22215                replace_range.clone()
22216            } else {
22217                insert_range.clone()
22218            }
22219        } else {
22220            replace_range.clone()
22221        }
22222    };
22223
22224    if range_to_replace
22225        .end
22226        .cmp(cursor_position, &buffer_snapshot)
22227        .is_lt()
22228    {
22229        range_to_replace.end = *cursor_position;
22230    }
22231
22232    CompletionEdit {
22233        new_text,
22234        replace_range: range_to_replace.to_offset(buffer),
22235        snippet,
22236    }
22237}
22238
22239struct CompletionEdit {
22240    new_text: String,
22241    replace_range: Range<usize>,
22242    snippet: Option<Snippet>,
22243}
22244
22245fn insert_extra_newline_brackets(
22246    buffer: &MultiBufferSnapshot,
22247    range: Range<usize>,
22248    language: &language::LanguageScope,
22249) -> bool {
22250    let leading_whitespace_len = buffer
22251        .reversed_chars_at(range.start)
22252        .take_while(|c| c.is_whitespace() && *c != '\n')
22253        .map(|c| c.len_utf8())
22254        .sum::<usize>();
22255    let trailing_whitespace_len = buffer
22256        .chars_at(range.end)
22257        .take_while(|c| c.is_whitespace() && *c != '\n')
22258        .map(|c| c.len_utf8())
22259        .sum::<usize>();
22260    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22261
22262    language.brackets().any(|(pair, enabled)| {
22263        let pair_start = pair.start.trim_end();
22264        let pair_end = pair.end.trim_start();
22265
22266        enabled
22267            && pair.newline
22268            && buffer.contains_str_at(range.end, pair_end)
22269            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22270    })
22271}
22272
22273fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22274    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22275        [(buffer, range, _)] => (*buffer, range.clone()),
22276        _ => return false,
22277    };
22278    let pair = {
22279        let mut result: Option<BracketMatch> = None;
22280
22281        for pair in buffer
22282            .all_bracket_ranges(range.clone())
22283            .filter(move |pair| {
22284                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22285            })
22286        {
22287            let len = pair.close_range.end - pair.open_range.start;
22288
22289            if let Some(existing) = &result {
22290                let existing_len = existing.close_range.end - existing.open_range.start;
22291                if len > existing_len {
22292                    continue;
22293                }
22294            }
22295
22296            result = Some(pair);
22297        }
22298
22299        result
22300    };
22301    let Some(pair) = pair else {
22302        return false;
22303    };
22304    pair.newline_only
22305        && buffer
22306            .chars_for_range(pair.open_range.end..range.start)
22307            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22308            .all(|c| c.is_whitespace() && c != '\n')
22309}
22310
22311fn update_uncommitted_diff_for_buffer(
22312    editor: Entity<Editor>,
22313    project: &Entity<Project>,
22314    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22315    buffer: Entity<MultiBuffer>,
22316    cx: &mut App,
22317) -> Task<()> {
22318    let mut tasks = Vec::new();
22319    project.update(cx, |project, cx| {
22320        for buffer in buffers {
22321            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22322                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22323            }
22324        }
22325    });
22326    cx.spawn(async move |cx| {
22327        let diffs = future::join_all(tasks).await;
22328        if editor
22329            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22330            .unwrap_or(false)
22331        {
22332            return;
22333        }
22334
22335        buffer
22336            .update(cx, |buffer, cx| {
22337                for diff in diffs.into_iter().flatten() {
22338                    buffer.add_diff(diff, cx);
22339                }
22340            })
22341            .ok();
22342    })
22343}
22344
22345fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22346    let tab_size = tab_size.get() as usize;
22347    let mut width = offset;
22348
22349    for ch in text.chars() {
22350        width += if ch == '\t' {
22351            tab_size - (width % tab_size)
22352        } else {
22353            1
22354        };
22355    }
22356
22357    width - offset
22358}
22359
22360#[cfg(test)]
22361mod tests {
22362    use super::*;
22363
22364    #[test]
22365    fn test_string_size_with_expanded_tabs() {
22366        let nz = |val| NonZeroU32::new(val).unwrap();
22367        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22368        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22369        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22370        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22371        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22372        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22373        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22374        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22375    }
22376}
22377
22378/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22379struct WordBreakingTokenizer<'a> {
22380    input: &'a str,
22381}
22382
22383impl<'a> WordBreakingTokenizer<'a> {
22384    fn new(input: &'a str) -> Self {
22385        Self { input }
22386    }
22387}
22388
22389fn is_char_ideographic(ch: char) -> bool {
22390    use unicode_script::Script::*;
22391    use unicode_script::UnicodeScript;
22392    matches!(ch.script(), Han | Tangut | Yi)
22393}
22394
22395fn is_grapheme_ideographic(text: &str) -> bool {
22396    text.chars().any(is_char_ideographic)
22397}
22398
22399fn is_grapheme_whitespace(text: &str) -> bool {
22400    text.chars().any(|x| x.is_whitespace())
22401}
22402
22403fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22404    text.chars()
22405        .next()
22406        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22407}
22408
22409#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22410enum WordBreakToken<'a> {
22411    Word { token: &'a str, grapheme_len: usize },
22412    InlineWhitespace { token: &'a str, grapheme_len: usize },
22413    Newline,
22414}
22415
22416impl<'a> Iterator for WordBreakingTokenizer<'a> {
22417    /// Yields a span, the count of graphemes in the token, and whether it was
22418    /// whitespace. Note that it also breaks at word boundaries.
22419    type Item = WordBreakToken<'a>;
22420
22421    fn next(&mut self) -> Option<Self::Item> {
22422        use unicode_segmentation::UnicodeSegmentation;
22423        if self.input.is_empty() {
22424            return None;
22425        }
22426
22427        let mut iter = self.input.graphemes(true).peekable();
22428        let mut offset = 0;
22429        let mut grapheme_len = 0;
22430        if let Some(first_grapheme) = iter.next() {
22431            let is_newline = first_grapheme == "\n";
22432            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22433            offset += first_grapheme.len();
22434            grapheme_len += 1;
22435            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22436                if let Some(grapheme) = iter.peek().copied()
22437                    && should_stay_with_preceding_ideograph(grapheme)
22438                {
22439                    offset += grapheme.len();
22440                    grapheme_len += 1;
22441                }
22442            } else {
22443                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22444                let mut next_word_bound = words.peek().copied();
22445                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22446                    next_word_bound = words.next();
22447                }
22448                while let Some(grapheme) = iter.peek().copied() {
22449                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22450                        break;
22451                    };
22452                    if is_grapheme_whitespace(grapheme) != is_whitespace
22453                        || (grapheme == "\n") != is_newline
22454                    {
22455                        break;
22456                    };
22457                    offset += grapheme.len();
22458                    grapheme_len += 1;
22459                    iter.next();
22460                }
22461            }
22462            let token = &self.input[..offset];
22463            self.input = &self.input[offset..];
22464            if token == "\n" {
22465                Some(WordBreakToken::Newline)
22466            } else if is_whitespace {
22467                Some(WordBreakToken::InlineWhitespace {
22468                    token,
22469                    grapheme_len,
22470                })
22471            } else {
22472                Some(WordBreakToken::Word {
22473                    token,
22474                    grapheme_len,
22475                })
22476            }
22477        } else {
22478            None
22479        }
22480    }
22481}
22482
22483#[test]
22484fn test_word_breaking_tokenizer() {
22485    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22486        ("", &[]),
22487        ("  ", &[whitespace("  ", 2)]),
22488        ("Ʒ", &[word("Ʒ", 1)]),
22489        ("Ǽ", &[word("Ǽ", 1)]),
22490        ("", &[word("", 1)]),
22491        ("⋑⋑", &[word("⋑⋑", 2)]),
22492        (
22493            "原理,进而",
22494            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22495        ),
22496        (
22497            "hello world",
22498            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22499        ),
22500        (
22501            "hello, world",
22502            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22503        ),
22504        (
22505            "  hello world",
22506            &[
22507                whitespace("  ", 2),
22508                word("hello", 5),
22509                whitespace(" ", 1),
22510                word("world", 5),
22511            ],
22512        ),
22513        (
22514            "这是什么 \n 钢笔",
22515            &[
22516                word("", 1),
22517                word("", 1),
22518                word("", 1),
22519                word("", 1),
22520                whitespace(" ", 1),
22521                newline(),
22522                whitespace(" ", 1),
22523                word("", 1),
22524                word("", 1),
22525            ],
22526        ),
22527        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22528    ];
22529
22530    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22531        WordBreakToken::Word {
22532            token,
22533            grapheme_len,
22534        }
22535    }
22536
22537    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22538        WordBreakToken::InlineWhitespace {
22539            token,
22540            grapheme_len,
22541        }
22542    }
22543
22544    fn newline() -> WordBreakToken<'static> {
22545        WordBreakToken::Newline
22546    }
22547
22548    for (input, result) in tests {
22549        assert_eq!(
22550            WordBreakingTokenizer::new(input)
22551                .collect::<Vec<_>>()
22552                .as_slice(),
22553            *result,
22554        );
22555    }
22556}
22557
22558fn wrap_with_prefix(
22559    first_line_prefix: String,
22560    subsequent_lines_prefix: String,
22561    unwrapped_text: String,
22562    wrap_column: usize,
22563    tab_size: NonZeroU32,
22564    preserve_existing_whitespace: bool,
22565) -> String {
22566    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22567    let subsequent_lines_prefix_len =
22568        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22569    let mut wrapped_text = String::new();
22570    let mut current_line = first_line_prefix;
22571    let mut is_first_line = true;
22572
22573    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22574    let mut current_line_len = first_line_prefix_len;
22575    let mut in_whitespace = false;
22576    for token in tokenizer {
22577        let have_preceding_whitespace = in_whitespace;
22578        match token {
22579            WordBreakToken::Word {
22580                token,
22581                grapheme_len,
22582            } => {
22583                in_whitespace = false;
22584                let current_prefix_len = if is_first_line {
22585                    first_line_prefix_len
22586                } else {
22587                    subsequent_lines_prefix_len
22588                };
22589                if current_line_len + grapheme_len > wrap_column
22590                    && current_line_len != current_prefix_len
22591                {
22592                    wrapped_text.push_str(current_line.trim_end());
22593                    wrapped_text.push('\n');
22594                    is_first_line = false;
22595                    current_line = subsequent_lines_prefix.clone();
22596                    current_line_len = subsequent_lines_prefix_len;
22597                }
22598                current_line.push_str(token);
22599                current_line_len += grapheme_len;
22600            }
22601            WordBreakToken::InlineWhitespace {
22602                mut token,
22603                mut grapheme_len,
22604            } => {
22605                in_whitespace = true;
22606                if have_preceding_whitespace && !preserve_existing_whitespace {
22607                    continue;
22608                }
22609                if !preserve_existing_whitespace {
22610                    // Keep a single whitespace grapheme as-is
22611                    if let Some(first) =
22612                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22613                    {
22614                        token = first;
22615                    } else {
22616                        token = " ";
22617                    }
22618                    grapheme_len = 1;
22619                }
22620                let current_prefix_len = if is_first_line {
22621                    first_line_prefix_len
22622                } else {
22623                    subsequent_lines_prefix_len
22624                };
22625                if current_line_len + grapheme_len > wrap_column {
22626                    wrapped_text.push_str(current_line.trim_end());
22627                    wrapped_text.push('\n');
22628                    is_first_line = false;
22629                    current_line = subsequent_lines_prefix.clone();
22630                    current_line_len = subsequent_lines_prefix_len;
22631                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22632                    current_line.push_str(token);
22633                    current_line_len += grapheme_len;
22634                }
22635            }
22636            WordBreakToken::Newline => {
22637                in_whitespace = true;
22638                let current_prefix_len = if is_first_line {
22639                    first_line_prefix_len
22640                } else {
22641                    subsequent_lines_prefix_len
22642                };
22643                if preserve_existing_whitespace {
22644                    wrapped_text.push_str(current_line.trim_end());
22645                    wrapped_text.push('\n');
22646                    is_first_line = false;
22647                    current_line = subsequent_lines_prefix.clone();
22648                    current_line_len = subsequent_lines_prefix_len;
22649                } else if have_preceding_whitespace {
22650                    continue;
22651                } else if current_line_len + 1 > wrap_column
22652                    && current_line_len != current_prefix_len
22653                {
22654                    wrapped_text.push_str(current_line.trim_end());
22655                    wrapped_text.push('\n');
22656                    is_first_line = false;
22657                    current_line = subsequent_lines_prefix.clone();
22658                    current_line_len = subsequent_lines_prefix_len;
22659                } else if current_line_len != current_prefix_len {
22660                    current_line.push(' ');
22661                    current_line_len += 1;
22662                }
22663            }
22664        }
22665    }
22666
22667    if !current_line.is_empty() {
22668        wrapped_text.push_str(&current_line);
22669    }
22670    wrapped_text
22671}
22672
22673#[test]
22674fn test_wrap_with_prefix() {
22675    assert_eq!(
22676        wrap_with_prefix(
22677            "# ".to_string(),
22678            "# ".to_string(),
22679            "abcdefg".to_string(),
22680            4,
22681            NonZeroU32::new(4).unwrap(),
22682            false,
22683        ),
22684        "# abcdefg"
22685    );
22686    assert_eq!(
22687        wrap_with_prefix(
22688            "".to_string(),
22689            "".to_string(),
22690            "\thello world".to_string(),
22691            8,
22692            NonZeroU32::new(4).unwrap(),
22693            false,
22694        ),
22695        "hello\nworld"
22696    );
22697    assert_eq!(
22698        wrap_with_prefix(
22699            "// ".to_string(),
22700            "// ".to_string(),
22701            "xx \nyy zz aa bb cc".to_string(),
22702            12,
22703            NonZeroU32::new(4).unwrap(),
22704            false,
22705        ),
22706        "// xx yy zz\n// aa bb cc"
22707    );
22708    assert_eq!(
22709        wrap_with_prefix(
22710            String::new(),
22711            String::new(),
22712            "这是什么 \n 钢笔".to_string(),
22713            3,
22714            NonZeroU32::new(4).unwrap(),
22715            false,
22716        ),
22717        "这是什\n么 钢\n"
22718    );
22719    assert_eq!(
22720        wrap_with_prefix(
22721            String::new(),
22722            String::new(),
22723            format!("foo{}bar", '\u{2009}'), // thin space
22724            80,
22725            NonZeroU32::new(4).unwrap(),
22726            false,
22727        ),
22728        format!("foo{}bar", '\u{2009}')
22729    );
22730}
22731
22732pub trait CollaborationHub {
22733    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22734    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22735    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22736}
22737
22738impl CollaborationHub for Entity<Project> {
22739    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22740        self.read(cx).collaborators()
22741    }
22742
22743    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22744        self.read(cx).user_store().read(cx).participant_indices()
22745    }
22746
22747    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22748        let this = self.read(cx);
22749        let user_ids = this.collaborators().values().map(|c| c.user_id);
22750        this.user_store().read(cx).participant_names(user_ids, cx)
22751    }
22752}
22753
22754pub trait SemanticsProvider {
22755    fn hover(
22756        &self,
22757        buffer: &Entity<Buffer>,
22758        position: text::Anchor,
22759        cx: &mut App,
22760    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22761
22762    fn inline_values(
22763        &self,
22764        buffer_handle: Entity<Buffer>,
22765        range: Range<text::Anchor>,
22766        cx: &mut App,
22767    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22768
22769    fn inlay_hints(
22770        &self,
22771        buffer_handle: Entity<Buffer>,
22772        range: Range<text::Anchor>,
22773        cx: &mut App,
22774    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22775
22776    fn resolve_inlay_hint(
22777        &self,
22778        hint: InlayHint,
22779        buffer_handle: Entity<Buffer>,
22780        server_id: LanguageServerId,
22781        cx: &mut App,
22782    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22783
22784    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22785
22786    fn document_highlights(
22787        &self,
22788        buffer: &Entity<Buffer>,
22789        position: text::Anchor,
22790        cx: &mut App,
22791    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22792
22793    fn definitions(
22794        &self,
22795        buffer: &Entity<Buffer>,
22796        position: text::Anchor,
22797        kind: GotoDefinitionKind,
22798        cx: &mut App,
22799    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22800
22801    fn range_for_rename(
22802        &self,
22803        buffer: &Entity<Buffer>,
22804        position: text::Anchor,
22805        cx: &mut App,
22806    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22807
22808    fn perform_rename(
22809        &self,
22810        buffer: &Entity<Buffer>,
22811        position: text::Anchor,
22812        new_name: String,
22813        cx: &mut App,
22814    ) -> Option<Task<Result<ProjectTransaction>>>;
22815}
22816
22817pub trait CompletionProvider {
22818    fn completions(
22819        &self,
22820        excerpt_id: ExcerptId,
22821        buffer: &Entity<Buffer>,
22822        buffer_position: text::Anchor,
22823        trigger: CompletionContext,
22824        window: &mut Window,
22825        cx: &mut Context<Editor>,
22826    ) -> Task<Result<Vec<CompletionResponse>>>;
22827
22828    fn resolve_completions(
22829        &self,
22830        _buffer: Entity<Buffer>,
22831        _completion_indices: Vec<usize>,
22832        _completions: Rc<RefCell<Box<[Completion]>>>,
22833        _cx: &mut Context<Editor>,
22834    ) -> Task<Result<bool>> {
22835        Task::ready(Ok(false))
22836    }
22837
22838    fn apply_additional_edits_for_completion(
22839        &self,
22840        _buffer: Entity<Buffer>,
22841        _completions: Rc<RefCell<Box<[Completion]>>>,
22842        _completion_index: usize,
22843        _push_to_history: bool,
22844        _cx: &mut Context<Editor>,
22845    ) -> Task<Result<Option<language::Transaction>>> {
22846        Task::ready(Ok(None))
22847    }
22848
22849    fn is_completion_trigger(
22850        &self,
22851        buffer: &Entity<Buffer>,
22852        position: language::Anchor,
22853        text: &str,
22854        trigger_in_words: bool,
22855        menu_is_open: bool,
22856        cx: &mut Context<Editor>,
22857    ) -> bool;
22858
22859    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22860
22861    fn sort_completions(&self) -> bool {
22862        true
22863    }
22864
22865    fn filter_completions(&self) -> bool {
22866        true
22867    }
22868}
22869
22870pub trait CodeActionProvider {
22871    fn id(&self) -> Arc<str>;
22872
22873    fn code_actions(
22874        &self,
22875        buffer: &Entity<Buffer>,
22876        range: Range<text::Anchor>,
22877        window: &mut Window,
22878        cx: &mut App,
22879    ) -> Task<Result<Vec<CodeAction>>>;
22880
22881    fn apply_code_action(
22882        &self,
22883        buffer_handle: Entity<Buffer>,
22884        action: CodeAction,
22885        excerpt_id: ExcerptId,
22886        push_to_history: bool,
22887        window: &mut Window,
22888        cx: &mut App,
22889    ) -> Task<Result<ProjectTransaction>>;
22890}
22891
22892impl CodeActionProvider for Entity<Project> {
22893    fn id(&self) -> Arc<str> {
22894        "project".into()
22895    }
22896
22897    fn code_actions(
22898        &self,
22899        buffer: &Entity<Buffer>,
22900        range: Range<text::Anchor>,
22901        _window: &mut Window,
22902        cx: &mut App,
22903    ) -> Task<Result<Vec<CodeAction>>> {
22904        self.update(cx, |project, cx| {
22905            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22906            let code_actions = project.code_actions(buffer, range, None, cx);
22907            cx.background_spawn(async move {
22908                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22909                Ok(code_lens_actions
22910                    .context("code lens fetch")?
22911                    .into_iter()
22912                    .flatten()
22913                    .chain(
22914                        code_actions
22915                            .context("code action fetch")?
22916                            .into_iter()
22917                            .flatten(),
22918                    )
22919                    .collect())
22920            })
22921        })
22922    }
22923
22924    fn apply_code_action(
22925        &self,
22926        buffer_handle: Entity<Buffer>,
22927        action: CodeAction,
22928        _excerpt_id: ExcerptId,
22929        push_to_history: bool,
22930        _window: &mut Window,
22931        cx: &mut App,
22932    ) -> Task<Result<ProjectTransaction>> {
22933        self.update(cx, |project, cx| {
22934            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22935        })
22936    }
22937}
22938
22939fn snippet_completions(
22940    project: &Project,
22941    buffer: &Entity<Buffer>,
22942    buffer_position: text::Anchor,
22943    cx: &mut App,
22944) -> Task<Result<CompletionResponse>> {
22945    let languages = buffer.read(cx).languages_at(buffer_position);
22946    let snippet_store = project.snippets().read(cx);
22947
22948    let scopes: Vec<_> = languages
22949        .iter()
22950        .filter_map(|language| {
22951            let language_name = language.lsp_id();
22952            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22953
22954            if snippets.is_empty() {
22955                None
22956            } else {
22957                Some((language.default_scope(), snippets))
22958            }
22959        })
22960        .collect();
22961
22962    if scopes.is_empty() {
22963        return Task::ready(Ok(CompletionResponse {
22964            completions: vec![],
22965            display_options: CompletionDisplayOptions::default(),
22966            is_incomplete: false,
22967        }));
22968    }
22969
22970    let snapshot = buffer.read(cx).text_snapshot();
22971    let executor = cx.background_executor().clone();
22972
22973    cx.background_spawn(async move {
22974        let mut is_incomplete = false;
22975        let mut completions: Vec<Completion> = Vec::new();
22976        for (scope, snippets) in scopes.into_iter() {
22977            let classifier =
22978                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22979
22980            const MAX_WORD_PREFIX_LEN: usize = 128;
22981            let last_word: String = snapshot
22982                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22983                .take(MAX_WORD_PREFIX_LEN)
22984                .take_while(|c| classifier.is_word(*c))
22985                .collect::<String>()
22986                .chars()
22987                .rev()
22988                .collect();
22989
22990            if last_word.is_empty() {
22991                return Ok(CompletionResponse {
22992                    completions: vec![],
22993                    display_options: CompletionDisplayOptions::default(),
22994                    is_incomplete: true,
22995                });
22996            }
22997
22998            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22999            let to_lsp = |point: &text::Anchor| {
23000                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23001                point_to_lsp(end)
23002            };
23003            let lsp_end = to_lsp(&buffer_position);
23004
23005            let candidates = snippets
23006                .iter()
23007                .enumerate()
23008                .flat_map(|(ix, snippet)| {
23009                    snippet
23010                        .prefix
23011                        .iter()
23012                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23013                })
23014                .collect::<Vec<StringMatchCandidate>>();
23015
23016            const MAX_RESULTS: usize = 100;
23017            let mut matches = fuzzy::match_strings(
23018                &candidates,
23019                &last_word,
23020                last_word.chars().any(|c| c.is_uppercase()),
23021                true,
23022                MAX_RESULTS,
23023                &Default::default(),
23024                executor.clone(),
23025            )
23026            .await;
23027
23028            if matches.len() >= MAX_RESULTS {
23029                is_incomplete = true;
23030            }
23031
23032            // Remove all candidates where the query's start does not match the start of any word in the candidate
23033            if let Some(query_start) = last_word.chars().next() {
23034                matches.retain(|string_match| {
23035                    split_words(&string_match.string).any(|word| {
23036                        // Check that the first codepoint of the word as lowercase matches the first
23037                        // codepoint of the query as lowercase
23038                        word.chars()
23039                            .flat_map(|codepoint| codepoint.to_lowercase())
23040                            .zip(query_start.to_lowercase())
23041                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23042                    })
23043                });
23044            }
23045
23046            let matched_strings = matches
23047                .into_iter()
23048                .map(|m| m.string)
23049                .collect::<HashSet<_>>();
23050
23051            completions.extend(snippets.iter().filter_map(|snippet| {
23052                let matching_prefix = snippet
23053                    .prefix
23054                    .iter()
23055                    .find(|prefix| matched_strings.contains(*prefix))?;
23056                let start = as_offset - last_word.len();
23057                let start = snapshot.anchor_before(start);
23058                let range = start..buffer_position;
23059                let lsp_start = to_lsp(&start);
23060                let lsp_range = lsp::Range {
23061                    start: lsp_start,
23062                    end: lsp_end,
23063                };
23064                Some(Completion {
23065                    replace_range: range,
23066                    new_text: snippet.body.clone(),
23067                    source: CompletionSource::Lsp {
23068                        insert_range: None,
23069                        server_id: LanguageServerId(usize::MAX),
23070                        resolved: true,
23071                        lsp_completion: Box::new(lsp::CompletionItem {
23072                            label: snippet.prefix.first().unwrap().clone(),
23073                            kind: Some(CompletionItemKind::SNIPPET),
23074                            label_details: snippet.description.as_ref().map(|description| {
23075                                lsp::CompletionItemLabelDetails {
23076                                    detail: Some(description.clone()),
23077                                    description: None,
23078                                }
23079                            }),
23080                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23081                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23082                                lsp::InsertReplaceEdit {
23083                                    new_text: snippet.body.clone(),
23084                                    insert: lsp_range,
23085                                    replace: lsp_range,
23086                                },
23087                            )),
23088                            filter_text: Some(snippet.body.clone()),
23089                            sort_text: Some(char::MAX.to_string()),
23090                            ..lsp::CompletionItem::default()
23091                        }),
23092                        lsp_defaults: None,
23093                    },
23094                    label: CodeLabel::plain(matching_prefix.clone(), None),
23095                    icon_path: None,
23096                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23097                        single_line: snippet.name.clone().into(),
23098                        plain_text: snippet
23099                            .description
23100                            .clone()
23101                            .map(|description| description.into()),
23102                    }),
23103                    insert_text_mode: None,
23104                    confirm: None,
23105                })
23106            }))
23107        }
23108
23109        Ok(CompletionResponse {
23110            completions,
23111            display_options: CompletionDisplayOptions::default(),
23112            is_incomplete,
23113        })
23114    })
23115}
23116
23117impl CompletionProvider for Entity<Project> {
23118    fn completions(
23119        &self,
23120        _excerpt_id: ExcerptId,
23121        buffer: &Entity<Buffer>,
23122        buffer_position: text::Anchor,
23123        options: CompletionContext,
23124        _window: &mut Window,
23125        cx: &mut Context<Editor>,
23126    ) -> Task<Result<Vec<CompletionResponse>>> {
23127        self.update(cx, |project, cx| {
23128            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23129            let project_completions = project.completions(buffer, buffer_position, options, cx);
23130            cx.background_spawn(async move {
23131                let mut responses = project_completions.await?;
23132                let snippets = snippets.await?;
23133                if !snippets.completions.is_empty() {
23134                    responses.push(snippets);
23135                }
23136                Ok(responses)
23137            })
23138        })
23139    }
23140
23141    fn resolve_completions(
23142        &self,
23143        buffer: Entity<Buffer>,
23144        completion_indices: Vec<usize>,
23145        completions: Rc<RefCell<Box<[Completion]>>>,
23146        cx: &mut Context<Editor>,
23147    ) -> Task<Result<bool>> {
23148        self.update(cx, |project, cx| {
23149            project.lsp_store().update(cx, |lsp_store, cx| {
23150                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23151            })
23152        })
23153    }
23154
23155    fn apply_additional_edits_for_completion(
23156        &self,
23157        buffer: Entity<Buffer>,
23158        completions: Rc<RefCell<Box<[Completion]>>>,
23159        completion_index: usize,
23160        push_to_history: bool,
23161        cx: &mut Context<Editor>,
23162    ) -> Task<Result<Option<language::Transaction>>> {
23163        self.update(cx, |project, cx| {
23164            project.lsp_store().update(cx, |lsp_store, cx| {
23165                lsp_store.apply_additional_edits_for_completion(
23166                    buffer,
23167                    completions,
23168                    completion_index,
23169                    push_to_history,
23170                    cx,
23171                )
23172            })
23173        })
23174    }
23175
23176    fn is_completion_trigger(
23177        &self,
23178        buffer: &Entity<Buffer>,
23179        position: language::Anchor,
23180        text: &str,
23181        trigger_in_words: bool,
23182        menu_is_open: bool,
23183        cx: &mut Context<Editor>,
23184    ) -> bool {
23185        let mut chars = text.chars();
23186        let char = if let Some(char) = chars.next() {
23187            char
23188        } else {
23189            return false;
23190        };
23191        if chars.next().is_some() {
23192            return false;
23193        }
23194
23195        let buffer = buffer.read(cx);
23196        let snapshot = buffer.snapshot();
23197        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23198            return false;
23199        }
23200        let classifier = snapshot
23201            .char_classifier_at(position)
23202            .scope_context(Some(CharScopeContext::Completion));
23203        if trigger_in_words && classifier.is_word(char) {
23204            return true;
23205        }
23206
23207        buffer.completion_triggers().contains(text)
23208    }
23209}
23210
23211impl SemanticsProvider for Entity<Project> {
23212    fn hover(
23213        &self,
23214        buffer: &Entity<Buffer>,
23215        position: text::Anchor,
23216        cx: &mut App,
23217    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23218        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23219    }
23220
23221    fn document_highlights(
23222        &self,
23223        buffer: &Entity<Buffer>,
23224        position: text::Anchor,
23225        cx: &mut App,
23226    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23227        Some(self.update(cx, |project, cx| {
23228            project.document_highlights(buffer, position, cx)
23229        }))
23230    }
23231
23232    fn definitions(
23233        &self,
23234        buffer: &Entity<Buffer>,
23235        position: text::Anchor,
23236        kind: GotoDefinitionKind,
23237        cx: &mut App,
23238    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23239        Some(self.update(cx, |project, cx| match kind {
23240            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23241            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23242            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23243            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23244        }))
23245    }
23246
23247    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23248        self.update(cx, |project, cx| {
23249            if project
23250                .active_debug_session(cx)
23251                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23252            {
23253                return true;
23254            }
23255
23256            buffer.update(cx, |buffer, cx| {
23257                project.any_language_server_supports_inlay_hints(buffer, cx)
23258            })
23259        })
23260    }
23261
23262    fn inline_values(
23263        &self,
23264        buffer_handle: Entity<Buffer>,
23265        range: Range<text::Anchor>,
23266        cx: &mut App,
23267    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23268        self.update(cx, |project, cx| {
23269            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23270
23271            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23272        })
23273    }
23274
23275    fn inlay_hints(
23276        &self,
23277        buffer_handle: Entity<Buffer>,
23278        range: Range<text::Anchor>,
23279        cx: &mut App,
23280    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23281        Some(self.update(cx, |project, cx| {
23282            project.inlay_hints(buffer_handle, range, cx)
23283        }))
23284    }
23285
23286    fn resolve_inlay_hint(
23287        &self,
23288        hint: InlayHint,
23289        buffer_handle: Entity<Buffer>,
23290        server_id: LanguageServerId,
23291        cx: &mut App,
23292    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23293        Some(self.update(cx, |project, cx| {
23294            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23295        }))
23296    }
23297
23298    fn range_for_rename(
23299        &self,
23300        buffer: &Entity<Buffer>,
23301        position: text::Anchor,
23302        cx: &mut App,
23303    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23304        Some(self.update(cx, |project, cx| {
23305            let buffer = buffer.clone();
23306            let task = project.prepare_rename(buffer.clone(), position, cx);
23307            cx.spawn(async move |_, cx| {
23308                Ok(match task.await? {
23309                    PrepareRenameResponse::Success(range) => Some(range),
23310                    PrepareRenameResponse::InvalidPosition => None,
23311                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23312                        // Fallback on using TreeSitter info to determine identifier range
23313                        buffer.read_with(cx, |buffer, _| {
23314                            let snapshot = buffer.snapshot();
23315                            let (range, kind) = snapshot.surrounding_word(position, None);
23316                            if kind != Some(CharKind::Word) {
23317                                return None;
23318                            }
23319                            Some(
23320                                snapshot.anchor_before(range.start)
23321                                    ..snapshot.anchor_after(range.end),
23322                            )
23323                        })?
23324                    }
23325                })
23326            })
23327        }))
23328    }
23329
23330    fn perform_rename(
23331        &self,
23332        buffer: &Entity<Buffer>,
23333        position: text::Anchor,
23334        new_name: String,
23335        cx: &mut App,
23336    ) -> Option<Task<Result<ProjectTransaction>>> {
23337        Some(self.update(cx, |project, cx| {
23338            project.perform_rename(buffer.clone(), position, new_name, cx)
23339        }))
23340    }
23341}
23342
23343fn inlay_hint_settings(
23344    location: Anchor,
23345    snapshot: &MultiBufferSnapshot,
23346    cx: &mut Context<Editor>,
23347) -> InlayHintSettings {
23348    let file = snapshot.file_at(location);
23349    let language = snapshot.language_at(location).map(|l| l.name());
23350    language_settings(language, file, cx).inlay_hints
23351}
23352
23353fn consume_contiguous_rows(
23354    contiguous_row_selections: &mut Vec<Selection<Point>>,
23355    selection: &Selection<Point>,
23356    display_map: &DisplaySnapshot,
23357    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23358) -> (MultiBufferRow, MultiBufferRow) {
23359    contiguous_row_selections.push(selection.clone());
23360    let start_row = starting_row(selection, display_map);
23361    let mut end_row = ending_row(selection, display_map);
23362
23363    while let Some(next_selection) = selections.peek() {
23364        if next_selection.start.row <= end_row.0 {
23365            end_row = ending_row(next_selection, display_map);
23366            contiguous_row_selections.push(selections.next().unwrap().clone());
23367        } else {
23368            break;
23369        }
23370    }
23371    (start_row, end_row)
23372}
23373
23374fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23375    if selection.start.column > 0 {
23376        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23377    } else {
23378        MultiBufferRow(selection.start.row)
23379    }
23380}
23381
23382fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23383    if next_selection.end.column > 0 || next_selection.is_empty() {
23384        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23385    } else {
23386        MultiBufferRow(next_selection.end.row)
23387    }
23388}
23389
23390impl EditorSnapshot {
23391    pub fn remote_selections_in_range<'a>(
23392        &'a self,
23393        range: &'a Range<Anchor>,
23394        collaboration_hub: &dyn CollaborationHub,
23395        cx: &'a App,
23396    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23397        let participant_names = collaboration_hub.user_names(cx);
23398        let participant_indices = collaboration_hub.user_participant_indices(cx);
23399        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23400        let collaborators_by_replica_id = collaborators_by_peer_id
23401            .values()
23402            .map(|collaborator| (collaborator.replica_id, collaborator))
23403            .collect::<HashMap<_, _>>();
23404        self.buffer_snapshot()
23405            .selections_in_range(range, false)
23406            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23407                if replica_id == AGENT_REPLICA_ID {
23408                    Some(RemoteSelection {
23409                        replica_id,
23410                        selection,
23411                        cursor_shape,
23412                        line_mode,
23413                        collaborator_id: CollaboratorId::Agent,
23414                        user_name: Some("Agent".into()),
23415                        color: cx.theme().players().agent(),
23416                    })
23417                } else {
23418                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23419                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23420                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23421                    Some(RemoteSelection {
23422                        replica_id,
23423                        selection,
23424                        cursor_shape,
23425                        line_mode,
23426                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23427                        user_name,
23428                        color: if let Some(index) = participant_index {
23429                            cx.theme().players().color_for_participant(index.0)
23430                        } else {
23431                            cx.theme().players().absent()
23432                        },
23433                    })
23434                }
23435            })
23436    }
23437
23438    pub fn hunks_for_ranges(
23439        &self,
23440        ranges: impl IntoIterator<Item = Range<Point>>,
23441    ) -> Vec<MultiBufferDiffHunk> {
23442        let mut hunks = Vec::new();
23443        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23444            HashMap::default();
23445        for query_range in ranges {
23446            let query_rows =
23447                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23448            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23449                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23450            ) {
23451                // Include deleted hunks that are adjacent to the query range, because
23452                // otherwise they would be missed.
23453                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23454                if hunk.status().is_deleted() {
23455                    intersects_range |= hunk.row_range.start == query_rows.end;
23456                    intersects_range |= hunk.row_range.end == query_rows.start;
23457                }
23458                if intersects_range {
23459                    if !processed_buffer_rows
23460                        .entry(hunk.buffer_id)
23461                        .or_default()
23462                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23463                    {
23464                        continue;
23465                    }
23466                    hunks.push(hunk);
23467                }
23468            }
23469        }
23470
23471        hunks
23472    }
23473
23474    fn display_diff_hunks_for_rows<'a>(
23475        &'a self,
23476        display_rows: Range<DisplayRow>,
23477        folded_buffers: &'a HashSet<BufferId>,
23478    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23479        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23480        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23481
23482        self.buffer_snapshot()
23483            .diff_hunks_in_range(buffer_start..buffer_end)
23484            .filter_map(|hunk| {
23485                if folded_buffers.contains(&hunk.buffer_id) {
23486                    return None;
23487                }
23488
23489                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23490                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23491
23492                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23493                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23494
23495                let display_hunk = if hunk_display_start.column() != 0 {
23496                    DisplayDiffHunk::Folded {
23497                        display_row: hunk_display_start.row(),
23498                    }
23499                } else {
23500                    let mut end_row = hunk_display_end.row();
23501                    if hunk_display_end.column() > 0 {
23502                        end_row.0 += 1;
23503                    }
23504                    let is_created_file = hunk.is_created_file();
23505                    DisplayDiffHunk::Unfolded {
23506                        status: hunk.status(),
23507                        diff_base_byte_range: hunk.diff_base_byte_range,
23508                        display_row_range: hunk_display_start.row()..end_row,
23509                        multi_buffer_range: Anchor::range_in_buffer(
23510                            hunk.excerpt_id,
23511                            hunk.buffer_id,
23512                            hunk.buffer_range,
23513                        ),
23514                        is_created_file,
23515                    }
23516                };
23517
23518                Some(display_hunk)
23519            })
23520    }
23521
23522    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23523        self.display_snapshot
23524            .buffer_snapshot()
23525            .language_at(position)
23526    }
23527
23528    pub fn is_focused(&self) -> bool {
23529        self.is_focused
23530    }
23531
23532    pub fn placeholder_text(&self) -> Option<String> {
23533        self.placeholder_display_snapshot
23534            .as_ref()
23535            .map(|display_map| display_map.text())
23536    }
23537
23538    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23539        self.scroll_anchor.scroll_position(&self.display_snapshot)
23540    }
23541
23542    fn gutter_dimensions(
23543        &self,
23544        font_id: FontId,
23545        font_size: Pixels,
23546        max_line_number_width: Pixels,
23547        cx: &App,
23548    ) -> Option<GutterDimensions> {
23549        if !self.show_gutter {
23550            return None;
23551        }
23552
23553        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23554        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23555
23556        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23557            matches!(
23558                ProjectSettings::get_global(cx).git.git_gutter,
23559                GitGutterSetting::TrackedFiles
23560            )
23561        });
23562        let gutter_settings = EditorSettings::get_global(cx).gutter;
23563        let show_line_numbers = self
23564            .show_line_numbers
23565            .unwrap_or(gutter_settings.line_numbers);
23566        let line_gutter_width = if show_line_numbers {
23567            // Avoid flicker-like gutter resizes when the line number gains another digit by
23568            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23569            let min_width_for_number_on_gutter =
23570                ch_advance * gutter_settings.min_line_number_digits as f32;
23571            max_line_number_width.max(min_width_for_number_on_gutter)
23572        } else {
23573            0.0.into()
23574        };
23575
23576        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23577        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23578
23579        let git_blame_entries_width =
23580            self.git_blame_gutter_max_author_length
23581                .map(|max_author_length| {
23582                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23583                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23584
23585                    /// The number of characters to dedicate to gaps and margins.
23586                    const SPACING_WIDTH: usize = 4;
23587
23588                    let max_char_count = max_author_length.min(renderer.max_author_length())
23589                        + ::git::SHORT_SHA_LENGTH
23590                        + MAX_RELATIVE_TIMESTAMP.len()
23591                        + SPACING_WIDTH;
23592
23593                    ch_advance * max_char_count
23594                });
23595
23596        let is_singleton = self.buffer_snapshot().is_singleton();
23597
23598        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23599        left_padding += if !is_singleton {
23600            ch_width * 4.0
23601        } else if show_runnables || show_breakpoints {
23602            ch_width * 3.0
23603        } else if show_git_gutter && show_line_numbers {
23604            ch_width * 2.0
23605        } else if show_git_gutter || show_line_numbers {
23606            ch_width
23607        } else {
23608            px(0.)
23609        };
23610
23611        let shows_folds = is_singleton && gutter_settings.folds;
23612
23613        let right_padding = if shows_folds && show_line_numbers {
23614            ch_width * 4.0
23615        } else if shows_folds || (!is_singleton && show_line_numbers) {
23616            ch_width * 3.0
23617        } else if show_line_numbers {
23618            ch_width
23619        } else {
23620            px(0.)
23621        };
23622
23623        Some(GutterDimensions {
23624            left_padding,
23625            right_padding,
23626            width: line_gutter_width + left_padding + right_padding,
23627            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23628            git_blame_entries_width,
23629        })
23630    }
23631
23632    pub fn render_crease_toggle(
23633        &self,
23634        buffer_row: MultiBufferRow,
23635        row_contains_cursor: bool,
23636        editor: Entity<Editor>,
23637        window: &mut Window,
23638        cx: &mut App,
23639    ) -> Option<AnyElement> {
23640        let folded = self.is_line_folded(buffer_row);
23641        let mut is_foldable = false;
23642
23643        if let Some(crease) = self
23644            .crease_snapshot
23645            .query_row(buffer_row, self.buffer_snapshot())
23646        {
23647            is_foldable = true;
23648            match crease {
23649                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23650                    if let Some(render_toggle) = render_toggle {
23651                        let toggle_callback =
23652                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23653                                if folded {
23654                                    editor.update(cx, |editor, cx| {
23655                                        editor.fold_at(buffer_row, window, cx)
23656                                    });
23657                                } else {
23658                                    editor.update(cx, |editor, cx| {
23659                                        editor.unfold_at(buffer_row, window, cx)
23660                                    });
23661                                }
23662                            });
23663                        return Some((render_toggle)(
23664                            buffer_row,
23665                            folded,
23666                            toggle_callback,
23667                            window,
23668                            cx,
23669                        ));
23670                    }
23671                }
23672            }
23673        }
23674
23675        is_foldable |= self.starts_indent(buffer_row);
23676
23677        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23678            Some(
23679                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23680                    .toggle_state(folded)
23681                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23682                        if folded {
23683                            this.unfold_at(buffer_row, window, cx);
23684                        } else {
23685                            this.fold_at(buffer_row, window, cx);
23686                        }
23687                    }))
23688                    .into_any_element(),
23689            )
23690        } else {
23691            None
23692        }
23693    }
23694
23695    pub fn render_crease_trailer(
23696        &self,
23697        buffer_row: MultiBufferRow,
23698        window: &mut Window,
23699        cx: &mut App,
23700    ) -> Option<AnyElement> {
23701        let folded = self.is_line_folded(buffer_row);
23702        if let Crease::Inline { render_trailer, .. } = self
23703            .crease_snapshot
23704            .query_row(buffer_row, self.buffer_snapshot())?
23705        {
23706            let render_trailer = render_trailer.as_ref()?;
23707            Some(render_trailer(buffer_row, folded, window, cx))
23708        } else {
23709            None
23710        }
23711    }
23712}
23713
23714impl Deref for EditorSnapshot {
23715    type Target = DisplaySnapshot;
23716
23717    fn deref(&self) -> &Self::Target {
23718        &self.display_snapshot
23719    }
23720}
23721
23722#[derive(Clone, Debug, PartialEq, Eq)]
23723pub enum EditorEvent {
23724    InputIgnored {
23725        text: Arc<str>,
23726    },
23727    InputHandled {
23728        utf16_range_to_replace: Option<Range<isize>>,
23729        text: Arc<str>,
23730    },
23731    ExcerptsAdded {
23732        buffer: Entity<Buffer>,
23733        predecessor: ExcerptId,
23734        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23735    },
23736    ExcerptsRemoved {
23737        ids: Vec<ExcerptId>,
23738        removed_buffer_ids: Vec<BufferId>,
23739    },
23740    BufferFoldToggled {
23741        ids: Vec<ExcerptId>,
23742        folded: bool,
23743    },
23744    ExcerptsEdited {
23745        ids: Vec<ExcerptId>,
23746    },
23747    ExcerptsExpanded {
23748        ids: Vec<ExcerptId>,
23749    },
23750    BufferEdited,
23751    Edited {
23752        transaction_id: clock::Lamport,
23753    },
23754    Reparsed(BufferId),
23755    Focused,
23756    FocusedIn,
23757    Blurred,
23758    DirtyChanged,
23759    Saved,
23760    TitleChanged,
23761    SelectionsChanged {
23762        local: bool,
23763    },
23764    ScrollPositionChanged {
23765        local: bool,
23766        autoscroll: bool,
23767    },
23768    TransactionUndone {
23769        transaction_id: clock::Lamport,
23770    },
23771    TransactionBegun {
23772        transaction_id: clock::Lamport,
23773    },
23774    CursorShapeChanged,
23775    BreadcrumbsChanged,
23776    PushedToNavHistory {
23777        anchor: Anchor,
23778        is_deactivate: bool,
23779    },
23780}
23781
23782impl EventEmitter<EditorEvent> for Editor {}
23783
23784impl Focusable for Editor {
23785    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23786        self.focus_handle.clone()
23787    }
23788}
23789
23790impl Render for Editor {
23791    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23792        let settings = ThemeSettings::get_global(cx);
23793
23794        let mut text_style = match self.mode {
23795            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23796                color: cx.theme().colors().editor_foreground,
23797                font_family: settings.ui_font.family.clone(),
23798                font_features: settings.ui_font.features.clone(),
23799                font_fallbacks: settings.ui_font.fallbacks.clone(),
23800                font_size: rems(0.875).into(),
23801                font_weight: settings.ui_font.weight,
23802                line_height: relative(settings.buffer_line_height.value()),
23803                ..Default::default()
23804            },
23805            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23806                color: cx.theme().colors().editor_foreground,
23807                font_family: settings.buffer_font.family.clone(),
23808                font_features: settings.buffer_font.features.clone(),
23809                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23810                font_size: settings.buffer_font_size(cx).into(),
23811                font_weight: settings.buffer_font.weight,
23812                line_height: relative(settings.buffer_line_height.value()),
23813                ..Default::default()
23814            },
23815        };
23816        if let Some(text_style_refinement) = &self.text_style_refinement {
23817            text_style.refine(text_style_refinement)
23818        }
23819
23820        let background = match self.mode {
23821            EditorMode::SingleLine => cx.theme().system().transparent,
23822            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23823            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23824            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23825        };
23826
23827        EditorElement::new(
23828            &cx.entity(),
23829            EditorStyle {
23830                background,
23831                border: cx.theme().colors().border,
23832                local_player: cx.theme().players().local(),
23833                text: text_style,
23834                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23835                syntax: cx.theme().syntax().clone(),
23836                status: cx.theme().status().clone(),
23837                inlay_hints_style: make_inlay_hints_style(cx),
23838                edit_prediction_styles: make_suggestion_styles(cx),
23839                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23840                show_underlines: self.diagnostics_enabled(),
23841            },
23842        )
23843    }
23844}
23845
23846impl EntityInputHandler for Editor {
23847    fn text_for_range(
23848        &mut self,
23849        range_utf16: Range<usize>,
23850        adjusted_range: &mut Option<Range<usize>>,
23851        _: &mut Window,
23852        cx: &mut Context<Self>,
23853    ) -> Option<String> {
23854        let snapshot = self.buffer.read(cx).read(cx);
23855        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23856        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23857        if (start.0..end.0) != range_utf16 {
23858            adjusted_range.replace(start.0..end.0);
23859        }
23860        Some(snapshot.text_for_range(start..end).collect())
23861    }
23862
23863    fn selected_text_range(
23864        &mut self,
23865        ignore_disabled_input: bool,
23866        _: &mut Window,
23867        cx: &mut Context<Self>,
23868    ) -> Option<UTF16Selection> {
23869        // Prevent the IME menu from appearing when holding down an alphabetic key
23870        // while input is disabled.
23871        if !ignore_disabled_input && !self.input_enabled {
23872            return None;
23873        }
23874
23875        let selection = self.selections.newest::<OffsetUtf16>(cx);
23876        let range = selection.range();
23877
23878        Some(UTF16Selection {
23879            range: range.start.0..range.end.0,
23880            reversed: selection.reversed,
23881        })
23882    }
23883
23884    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23885        let snapshot = self.buffer.read(cx).read(cx);
23886        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23887        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23888    }
23889
23890    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23891        self.clear_highlights::<InputComposition>(cx);
23892        self.ime_transaction.take();
23893    }
23894
23895    fn replace_text_in_range(
23896        &mut self,
23897        range_utf16: Option<Range<usize>>,
23898        text: &str,
23899        window: &mut Window,
23900        cx: &mut Context<Self>,
23901    ) {
23902        if !self.input_enabled {
23903            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23904            return;
23905        }
23906
23907        self.transact(window, cx, |this, window, cx| {
23908            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23909                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23910                Some(this.selection_replacement_ranges(range_utf16, cx))
23911            } else {
23912                this.marked_text_ranges(cx)
23913            };
23914
23915            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23916                let newest_selection_id = this.selections.newest_anchor().id;
23917                this.selections
23918                    .all::<OffsetUtf16>(cx)
23919                    .iter()
23920                    .zip(ranges_to_replace.iter())
23921                    .find_map(|(selection, range)| {
23922                        if selection.id == newest_selection_id {
23923                            Some(
23924                                (range.start.0 as isize - selection.head().0 as isize)
23925                                    ..(range.end.0 as isize - selection.head().0 as isize),
23926                            )
23927                        } else {
23928                            None
23929                        }
23930                    })
23931            });
23932
23933            cx.emit(EditorEvent::InputHandled {
23934                utf16_range_to_replace: range_to_replace,
23935                text: text.into(),
23936            });
23937
23938            if let Some(new_selected_ranges) = new_selected_ranges {
23939                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23940                    selections.select_ranges(new_selected_ranges)
23941                });
23942                this.backspace(&Default::default(), window, cx);
23943            }
23944
23945            this.handle_input(text, window, cx);
23946        });
23947
23948        if let Some(transaction) = self.ime_transaction {
23949            self.buffer.update(cx, |buffer, cx| {
23950                buffer.group_until_transaction(transaction, cx);
23951            });
23952        }
23953
23954        self.unmark_text(window, cx);
23955    }
23956
23957    fn replace_and_mark_text_in_range(
23958        &mut self,
23959        range_utf16: Option<Range<usize>>,
23960        text: &str,
23961        new_selected_range_utf16: Option<Range<usize>>,
23962        window: &mut Window,
23963        cx: &mut Context<Self>,
23964    ) {
23965        if !self.input_enabled {
23966            return;
23967        }
23968
23969        let transaction = self.transact(window, cx, |this, window, cx| {
23970            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23971                let snapshot = this.buffer.read(cx).read(cx);
23972                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23973                    for marked_range in &mut marked_ranges {
23974                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23975                        marked_range.start.0 += relative_range_utf16.start;
23976                        marked_range.start =
23977                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23978                        marked_range.end =
23979                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23980                    }
23981                }
23982                Some(marked_ranges)
23983            } else if let Some(range_utf16) = range_utf16 {
23984                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23985                Some(this.selection_replacement_ranges(range_utf16, cx))
23986            } else {
23987                None
23988            };
23989
23990            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23991                let newest_selection_id = this.selections.newest_anchor().id;
23992                this.selections
23993                    .all::<OffsetUtf16>(cx)
23994                    .iter()
23995                    .zip(ranges_to_replace.iter())
23996                    .find_map(|(selection, range)| {
23997                        if selection.id == newest_selection_id {
23998                            Some(
23999                                (range.start.0 as isize - selection.head().0 as isize)
24000                                    ..(range.end.0 as isize - selection.head().0 as isize),
24001                            )
24002                        } else {
24003                            None
24004                        }
24005                    })
24006            });
24007
24008            cx.emit(EditorEvent::InputHandled {
24009                utf16_range_to_replace: range_to_replace,
24010                text: text.into(),
24011            });
24012
24013            if let Some(ranges) = ranges_to_replace {
24014                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24015                    s.select_ranges(ranges)
24016                });
24017            }
24018
24019            let marked_ranges = {
24020                let snapshot = this.buffer.read(cx).read(cx);
24021                this.selections
24022                    .disjoint_anchors_arc()
24023                    .iter()
24024                    .map(|selection| {
24025                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24026                    })
24027                    .collect::<Vec<_>>()
24028            };
24029
24030            if text.is_empty() {
24031                this.unmark_text(window, cx);
24032            } else {
24033                this.highlight_text::<InputComposition>(
24034                    marked_ranges.clone(),
24035                    HighlightStyle {
24036                        underline: Some(UnderlineStyle {
24037                            thickness: px(1.),
24038                            color: None,
24039                            wavy: false,
24040                        }),
24041                        ..Default::default()
24042                    },
24043                    cx,
24044                );
24045            }
24046
24047            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24048            let use_autoclose = this.use_autoclose;
24049            let use_auto_surround = this.use_auto_surround;
24050            this.set_use_autoclose(false);
24051            this.set_use_auto_surround(false);
24052            this.handle_input(text, window, cx);
24053            this.set_use_autoclose(use_autoclose);
24054            this.set_use_auto_surround(use_auto_surround);
24055
24056            if let Some(new_selected_range) = new_selected_range_utf16 {
24057                let snapshot = this.buffer.read(cx).read(cx);
24058                let new_selected_ranges = marked_ranges
24059                    .into_iter()
24060                    .map(|marked_range| {
24061                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24062                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24063                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24064                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24065                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24066                    })
24067                    .collect::<Vec<_>>();
24068
24069                drop(snapshot);
24070                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24071                    selections.select_ranges(new_selected_ranges)
24072                });
24073            }
24074        });
24075
24076        self.ime_transaction = self.ime_transaction.or(transaction);
24077        if let Some(transaction) = self.ime_transaction {
24078            self.buffer.update(cx, |buffer, cx| {
24079                buffer.group_until_transaction(transaction, cx);
24080            });
24081        }
24082
24083        if self.text_highlights::<InputComposition>(cx).is_none() {
24084            self.ime_transaction.take();
24085        }
24086    }
24087
24088    fn bounds_for_range(
24089        &mut self,
24090        range_utf16: Range<usize>,
24091        element_bounds: gpui::Bounds<Pixels>,
24092        window: &mut Window,
24093        cx: &mut Context<Self>,
24094    ) -> Option<gpui::Bounds<Pixels>> {
24095        let text_layout_details = self.text_layout_details(window);
24096        let CharacterDimensions {
24097            em_width,
24098            em_advance,
24099            line_height,
24100        } = self.character_dimensions(window);
24101
24102        let snapshot = self.snapshot(window, cx);
24103        let scroll_position = snapshot.scroll_position();
24104        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24105
24106        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24107        let x = Pixels::from(
24108            ScrollOffset::from(
24109                snapshot.x_for_display_point(start, &text_layout_details)
24110                    + self.gutter_dimensions.full_width(),
24111            ) - scroll_left,
24112        );
24113        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24114
24115        Some(Bounds {
24116            origin: element_bounds.origin + point(x, y),
24117            size: size(em_width, line_height),
24118        })
24119    }
24120
24121    fn character_index_for_point(
24122        &mut self,
24123        point: gpui::Point<Pixels>,
24124        _window: &mut Window,
24125        _cx: &mut Context<Self>,
24126    ) -> Option<usize> {
24127        let position_map = self.last_position_map.as_ref()?;
24128        if !position_map.text_hitbox.contains(&point) {
24129            return None;
24130        }
24131        let display_point = position_map.point_for_position(point).previous_valid;
24132        let anchor = position_map
24133            .snapshot
24134            .display_point_to_anchor(display_point, Bias::Left);
24135        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24136        Some(utf16_offset.0)
24137    }
24138}
24139
24140trait SelectionExt {
24141    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24142    fn spanned_rows(
24143        &self,
24144        include_end_if_at_line_start: bool,
24145        map: &DisplaySnapshot,
24146    ) -> Range<MultiBufferRow>;
24147}
24148
24149impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24150    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24151        let start = self
24152            .start
24153            .to_point(map.buffer_snapshot())
24154            .to_display_point(map);
24155        let end = self
24156            .end
24157            .to_point(map.buffer_snapshot())
24158            .to_display_point(map);
24159        if self.reversed {
24160            end..start
24161        } else {
24162            start..end
24163        }
24164    }
24165
24166    fn spanned_rows(
24167        &self,
24168        include_end_if_at_line_start: bool,
24169        map: &DisplaySnapshot,
24170    ) -> Range<MultiBufferRow> {
24171        let start = self.start.to_point(map.buffer_snapshot());
24172        let mut end = self.end.to_point(map.buffer_snapshot());
24173        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24174            end.row -= 1;
24175        }
24176
24177        let buffer_start = map.prev_line_boundary(start).0;
24178        let buffer_end = map.next_line_boundary(end).0;
24179        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24180    }
24181}
24182
24183impl<T: InvalidationRegion> InvalidationStack<T> {
24184    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24185    where
24186        S: Clone + ToOffset,
24187    {
24188        while let Some(region) = self.last() {
24189            let all_selections_inside_invalidation_ranges =
24190                if selections.len() == region.ranges().len() {
24191                    selections
24192                        .iter()
24193                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24194                        .all(|(selection, invalidation_range)| {
24195                            let head = selection.head().to_offset(buffer);
24196                            invalidation_range.start <= head && invalidation_range.end >= head
24197                        })
24198                } else {
24199                    false
24200                };
24201
24202            if all_selections_inside_invalidation_ranges {
24203                break;
24204            } else {
24205                self.pop();
24206            }
24207        }
24208    }
24209}
24210
24211impl<T> Default for InvalidationStack<T> {
24212    fn default() -> Self {
24213        Self(Default::default())
24214    }
24215}
24216
24217impl<T> Deref for InvalidationStack<T> {
24218    type Target = Vec<T>;
24219
24220    fn deref(&self) -> &Self::Target {
24221        &self.0
24222    }
24223}
24224
24225impl<T> DerefMut for InvalidationStack<T> {
24226    fn deref_mut(&mut self) -> &mut Self::Target {
24227        &mut self.0
24228    }
24229}
24230
24231impl InvalidationRegion for SnippetState {
24232    fn ranges(&self) -> &[Range<Anchor>] {
24233        &self.ranges[self.active_index]
24234    }
24235}
24236
24237fn edit_prediction_edit_text(
24238    current_snapshot: &BufferSnapshot,
24239    edits: &[(Range<Anchor>, String)],
24240    edit_preview: &EditPreview,
24241    include_deletions: bool,
24242    cx: &App,
24243) -> HighlightedText {
24244    let edits = edits
24245        .iter()
24246        .map(|(anchor, text)| {
24247            (
24248                anchor.start.text_anchor..anchor.end.text_anchor,
24249                text.clone(),
24250            )
24251        })
24252        .collect::<Vec<_>>();
24253
24254    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24255}
24256
24257fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24258    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24259    // Just show the raw edit text with basic styling
24260    let mut text = String::new();
24261    let mut highlights = Vec::new();
24262
24263    let insertion_highlight_style = HighlightStyle {
24264        color: Some(cx.theme().colors().text),
24265        ..Default::default()
24266    };
24267
24268    for (_, edit_text) in edits {
24269        let start_offset = text.len();
24270        text.push_str(edit_text);
24271        let end_offset = text.len();
24272
24273        if start_offset < end_offset {
24274            highlights.push((start_offset..end_offset, insertion_highlight_style));
24275        }
24276    }
24277
24278    HighlightedText {
24279        text: text.into(),
24280        highlights,
24281    }
24282}
24283
24284pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24285    match severity {
24286        lsp::DiagnosticSeverity::ERROR => colors.error,
24287        lsp::DiagnosticSeverity::WARNING => colors.warning,
24288        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24289        lsp::DiagnosticSeverity::HINT => colors.info,
24290        _ => colors.ignored,
24291    }
24292}
24293
24294pub fn styled_runs_for_code_label<'a>(
24295    label: &'a CodeLabel,
24296    syntax_theme: &'a theme::SyntaxTheme,
24297) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24298    let fade_out = HighlightStyle {
24299        fade_out: Some(0.35),
24300        ..Default::default()
24301    };
24302
24303    let mut prev_end = label.filter_range.end;
24304    label
24305        .runs
24306        .iter()
24307        .enumerate()
24308        .flat_map(move |(ix, (range, highlight_id))| {
24309            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24310                style
24311            } else {
24312                return Default::default();
24313            };
24314            let muted_style = style.highlight(fade_out);
24315
24316            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24317            if range.start >= label.filter_range.end {
24318                if range.start > prev_end {
24319                    runs.push((prev_end..range.start, fade_out));
24320                }
24321                runs.push((range.clone(), muted_style));
24322            } else if range.end <= label.filter_range.end {
24323                runs.push((range.clone(), style));
24324            } else {
24325                runs.push((range.start..label.filter_range.end, style));
24326                runs.push((label.filter_range.end..range.end, muted_style));
24327            }
24328            prev_end = cmp::max(prev_end, range.end);
24329
24330            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24331                runs.push((prev_end..label.text.len(), fade_out));
24332            }
24333
24334            runs
24335        })
24336}
24337
24338pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24339    let mut prev_index = 0;
24340    let mut prev_codepoint: Option<char> = None;
24341    text.char_indices()
24342        .chain([(text.len(), '\0')])
24343        .filter_map(move |(index, codepoint)| {
24344            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24345            let is_boundary = index == text.len()
24346                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24347                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24348            if is_boundary {
24349                let chunk = &text[prev_index..index];
24350                prev_index = index;
24351                Some(chunk)
24352            } else {
24353                None
24354            }
24355        })
24356}
24357
24358pub trait RangeToAnchorExt: Sized {
24359    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24360
24361    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24362        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24363        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24364    }
24365}
24366
24367impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24368    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24369        let start_offset = self.start.to_offset(snapshot);
24370        let end_offset = self.end.to_offset(snapshot);
24371        if start_offset == end_offset {
24372            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24373        } else {
24374            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24375        }
24376    }
24377}
24378
24379pub trait RowExt {
24380    fn as_f64(&self) -> f64;
24381
24382    fn next_row(&self) -> Self;
24383
24384    fn previous_row(&self) -> Self;
24385
24386    fn minus(&self, other: Self) -> u32;
24387}
24388
24389impl RowExt for DisplayRow {
24390    fn as_f64(&self) -> f64 {
24391        self.0 as _
24392    }
24393
24394    fn next_row(&self) -> Self {
24395        Self(self.0 + 1)
24396    }
24397
24398    fn previous_row(&self) -> Self {
24399        Self(self.0.saturating_sub(1))
24400    }
24401
24402    fn minus(&self, other: Self) -> u32 {
24403        self.0 - other.0
24404    }
24405}
24406
24407impl RowExt for MultiBufferRow {
24408    fn as_f64(&self) -> f64 {
24409        self.0 as _
24410    }
24411
24412    fn next_row(&self) -> Self {
24413        Self(self.0 + 1)
24414    }
24415
24416    fn previous_row(&self) -> Self {
24417        Self(self.0.saturating_sub(1))
24418    }
24419
24420    fn minus(&self, other: Self) -> u32 {
24421        self.0 - other.0
24422    }
24423}
24424
24425trait RowRangeExt {
24426    type Row;
24427
24428    fn len(&self) -> usize;
24429
24430    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24431}
24432
24433impl RowRangeExt for Range<MultiBufferRow> {
24434    type Row = MultiBufferRow;
24435
24436    fn len(&self) -> usize {
24437        (self.end.0 - self.start.0) as usize
24438    }
24439
24440    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24441        (self.start.0..self.end.0).map(MultiBufferRow)
24442    }
24443}
24444
24445impl RowRangeExt for Range<DisplayRow> {
24446    type Row = DisplayRow;
24447
24448    fn len(&self) -> usize {
24449        (self.end.0 - self.start.0) as usize
24450    }
24451
24452    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24453        (self.start.0..self.end.0).map(DisplayRow)
24454    }
24455}
24456
24457/// If select range has more than one line, we
24458/// just point the cursor to range.start.
24459fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24460    if range.start.row == range.end.row {
24461        range
24462    } else {
24463        range.start..range.start
24464    }
24465}
24466pub struct KillRing(ClipboardItem);
24467impl Global for KillRing {}
24468
24469const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24470
24471enum BreakpointPromptEditAction {
24472    Log,
24473    Condition,
24474    HitCondition,
24475}
24476
24477struct BreakpointPromptEditor {
24478    pub(crate) prompt: Entity<Editor>,
24479    editor: WeakEntity<Editor>,
24480    breakpoint_anchor: Anchor,
24481    breakpoint: Breakpoint,
24482    edit_action: BreakpointPromptEditAction,
24483    block_ids: HashSet<CustomBlockId>,
24484    editor_margins: Arc<Mutex<EditorMargins>>,
24485    _subscriptions: Vec<Subscription>,
24486}
24487
24488impl BreakpointPromptEditor {
24489    const MAX_LINES: u8 = 4;
24490
24491    fn new(
24492        editor: WeakEntity<Editor>,
24493        breakpoint_anchor: Anchor,
24494        breakpoint: Breakpoint,
24495        edit_action: BreakpointPromptEditAction,
24496        window: &mut Window,
24497        cx: &mut Context<Self>,
24498    ) -> Self {
24499        let base_text = match edit_action {
24500            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24501            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24502            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24503        }
24504        .map(|msg| msg.to_string())
24505        .unwrap_or_default();
24506
24507        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24508        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24509
24510        let prompt = cx.new(|cx| {
24511            let mut prompt = Editor::new(
24512                EditorMode::AutoHeight {
24513                    min_lines: 1,
24514                    max_lines: Some(Self::MAX_LINES as usize),
24515                },
24516                buffer,
24517                None,
24518                window,
24519                cx,
24520            );
24521            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24522            prompt.set_show_cursor_when_unfocused(false, cx);
24523            prompt.set_placeholder_text(
24524                match edit_action {
24525                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24526                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24527                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24528                },
24529                window,
24530                cx,
24531            );
24532
24533            prompt
24534        });
24535
24536        Self {
24537            prompt,
24538            editor,
24539            breakpoint_anchor,
24540            breakpoint,
24541            edit_action,
24542            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24543            block_ids: Default::default(),
24544            _subscriptions: vec![],
24545        }
24546    }
24547
24548    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24549        self.block_ids.extend(block_ids)
24550    }
24551
24552    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24553        if let Some(editor) = self.editor.upgrade() {
24554            let message = self
24555                .prompt
24556                .read(cx)
24557                .buffer
24558                .read(cx)
24559                .as_singleton()
24560                .expect("A multi buffer in breakpoint prompt isn't possible")
24561                .read(cx)
24562                .as_rope()
24563                .to_string();
24564
24565            editor.update(cx, |editor, cx| {
24566                editor.edit_breakpoint_at_anchor(
24567                    self.breakpoint_anchor,
24568                    self.breakpoint.clone(),
24569                    match self.edit_action {
24570                        BreakpointPromptEditAction::Log => {
24571                            BreakpointEditAction::EditLogMessage(message.into())
24572                        }
24573                        BreakpointPromptEditAction::Condition => {
24574                            BreakpointEditAction::EditCondition(message.into())
24575                        }
24576                        BreakpointPromptEditAction::HitCondition => {
24577                            BreakpointEditAction::EditHitCondition(message.into())
24578                        }
24579                    },
24580                    cx,
24581                );
24582
24583                editor.remove_blocks(self.block_ids.clone(), None, cx);
24584                cx.focus_self(window);
24585            });
24586        }
24587    }
24588
24589    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24590        self.editor
24591            .update(cx, |editor, cx| {
24592                editor.remove_blocks(self.block_ids.clone(), None, cx);
24593                window.focus(&editor.focus_handle);
24594            })
24595            .log_err();
24596    }
24597
24598    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24599        let settings = ThemeSettings::get_global(cx);
24600        let text_style = TextStyle {
24601            color: if self.prompt.read(cx).read_only(cx) {
24602                cx.theme().colors().text_disabled
24603            } else {
24604                cx.theme().colors().text
24605            },
24606            font_family: settings.buffer_font.family.clone(),
24607            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24608            font_size: settings.buffer_font_size(cx).into(),
24609            font_weight: settings.buffer_font.weight,
24610            line_height: relative(settings.buffer_line_height.value()),
24611            ..Default::default()
24612        };
24613        EditorElement::new(
24614            &self.prompt,
24615            EditorStyle {
24616                background: cx.theme().colors().editor_background,
24617                local_player: cx.theme().players().local(),
24618                text: text_style,
24619                ..Default::default()
24620            },
24621        )
24622    }
24623}
24624
24625impl Render for BreakpointPromptEditor {
24626    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24627        let editor_margins = *self.editor_margins.lock();
24628        let gutter_dimensions = editor_margins.gutter;
24629        h_flex()
24630            .key_context("Editor")
24631            .bg(cx.theme().colors().editor_background)
24632            .border_y_1()
24633            .border_color(cx.theme().status().info_border)
24634            .size_full()
24635            .py(window.line_height() / 2.5)
24636            .on_action(cx.listener(Self::confirm))
24637            .on_action(cx.listener(Self::cancel))
24638            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24639            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24640    }
24641}
24642
24643impl Focusable for BreakpointPromptEditor {
24644    fn focus_handle(&self, cx: &App) -> FocusHandle {
24645        self.prompt.focus_handle(cx)
24646    }
24647}
24648
24649fn all_edits_insertions_or_deletions(
24650    edits: &Vec<(Range<Anchor>, String)>,
24651    snapshot: &MultiBufferSnapshot,
24652) -> bool {
24653    let mut all_insertions = true;
24654    let mut all_deletions = true;
24655
24656    for (range, new_text) in edits.iter() {
24657        let range_is_empty = range.to_offset(snapshot).is_empty();
24658        let text_is_empty = new_text.is_empty();
24659
24660        if range_is_empty != text_is_empty {
24661            if range_is_empty {
24662                all_deletions = false;
24663            } else {
24664                all_insertions = false;
24665            }
24666        } else {
24667            return false;
24668        }
24669
24670        if !all_insertions && !all_deletions {
24671            return false;
24672        }
24673    }
24674    all_insertions || all_deletions
24675}
24676
24677struct MissingEditPredictionKeybindingTooltip;
24678
24679impl Render for MissingEditPredictionKeybindingTooltip {
24680    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24681        ui::tooltip_container(cx, |container, cx| {
24682            container
24683                .flex_shrink_0()
24684                .max_w_80()
24685                .min_h(rems_from_px(124.))
24686                .justify_between()
24687                .child(
24688                    v_flex()
24689                        .flex_1()
24690                        .text_ui_sm(cx)
24691                        .child(Label::new("Conflict with Accept Keybinding"))
24692                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24693                )
24694                .child(
24695                    h_flex()
24696                        .pb_1()
24697                        .gap_1()
24698                        .items_end()
24699                        .w_full()
24700                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24701                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24702                        }))
24703                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24704                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24705                        })),
24706                )
24707        })
24708    }
24709}
24710
24711#[derive(Debug, Clone, Copy, PartialEq)]
24712pub struct LineHighlight {
24713    pub background: Background,
24714    pub border: Option<gpui::Hsla>,
24715    pub include_gutter: bool,
24716    pub type_id: Option<TypeId>,
24717}
24718
24719struct LineManipulationResult {
24720    pub new_text: String,
24721    pub line_count_before: usize,
24722    pub line_count_after: usize,
24723}
24724
24725fn render_diff_hunk_controls(
24726    row: u32,
24727    status: &DiffHunkStatus,
24728    hunk_range: Range<Anchor>,
24729    is_created_file: bool,
24730    line_height: Pixels,
24731    editor: &Entity<Editor>,
24732    _window: &mut Window,
24733    cx: &mut App,
24734) -> AnyElement {
24735    h_flex()
24736        .h(line_height)
24737        .mr_1()
24738        .gap_1()
24739        .px_0p5()
24740        .pb_1()
24741        .border_x_1()
24742        .border_b_1()
24743        .border_color(cx.theme().colors().border_variant)
24744        .rounded_b_lg()
24745        .bg(cx.theme().colors().editor_background)
24746        .gap_1()
24747        .block_mouse_except_scroll()
24748        .shadow_md()
24749        .child(if status.has_secondary_hunk() {
24750            Button::new(("stage", row as u64), "Stage")
24751                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24752                .tooltip({
24753                    let focus_handle = editor.focus_handle(cx);
24754                    move |window, cx| {
24755                        Tooltip::for_action_in(
24756                            "Stage Hunk",
24757                            &::git::ToggleStaged,
24758                            &focus_handle,
24759                            window,
24760                            cx,
24761                        )
24762                    }
24763                })
24764                .on_click({
24765                    let editor = editor.clone();
24766                    move |_event, _window, cx| {
24767                        editor.update(cx, |editor, cx| {
24768                            editor.stage_or_unstage_diff_hunks(
24769                                true,
24770                                vec![hunk_range.start..hunk_range.start],
24771                                cx,
24772                            );
24773                        });
24774                    }
24775                })
24776        } else {
24777            Button::new(("unstage", row as u64), "Unstage")
24778                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24779                .tooltip({
24780                    let focus_handle = editor.focus_handle(cx);
24781                    move |window, cx| {
24782                        Tooltip::for_action_in(
24783                            "Unstage Hunk",
24784                            &::git::ToggleStaged,
24785                            &focus_handle,
24786                            window,
24787                            cx,
24788                        )
24789                    }
24790                })
24791                .on_click({
24792                    let editor = editor.clone();
24793                    move |_event, _window, cx| {
24794                        editor.update(cx, |editor, cx| {
24795                            editor.stage_or_unstage_diff_hunks(
24796                                false,
24797                                vec![hunk_range.start..hunk_range.start],
24798                                cx,
24799                            );
24800                        });
24801                    }
24802                })
24803        })
24804        .child(
24805            Button::new(("restore", row as u64), "Restore")
24806                .tooltip({
24807                    let focus_handle = editor.focus_handle(cx);
24808                    move |window, cx| {
24809                        Tooltip::for_action_in(
24810                            "Restore Hunk",
24811                            &::git::Restore,
24812                            &focus_handle,
24813                            window,
24814                            cx,
24815                        )
24816                    }
24817                })
24818                .on_click({
24819                    let editor = editor.clone();
24820                    move |_event, window, cx| {
24821                        editor.update(cx, |editor, cx| {
24822                            let snapshot = editor.snapshot(window, cx);
24823                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24824                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24825                        });
24826                    }
24827                })
24828                .disabled(is_created_file),
24829        )
24830        .when(
24831            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24832            |el| {
24833                el.child(
24834                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24835                        .shape(IconButtonShape::Square)
24836                        .icon_size(IconSize::Small)
24837                        // .disabled(!has_multiple_hunks)
24838                        .tooltip({
24839                            let focus_handle = editor.focus_handle(cx);
24840                            move |window, cx| {
24841                                Tooltip::for_action_in(
24842                                    "Next Hunk",
24843                                    &GoToHunk,
24844                                    &focus_handle,
24845                                    window,
24846                                    cx,
24847                                )
24848                            }
24849                        })
24850                        .on_click({
24851                            let editor = editor.clone();
24852                            move |_event, window, cx| {
24853                                editor.update(cx, |editor, cx| {
24854                                    let snapshot = editor.snapshot(window, cx);
24855                                    let position =
24856                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24857                                    editor.go_to_hunk_before_or_after_position(
24858                                        &snapshot,
24859                                        position,
24860                                        Direction::Next,
24861                                        window,
24862                                        cx,
24863                                    );
24864                                    editor.expand_selected_diff_hunks(cx);
24865                                });
24866                            }
24867                        }),
24868                )
24869                .child(
24870                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24871                        .shape(IconButtonShape::Square)
24872                        .icon_size(IconSize::Small)
24873                        // .disabled(!has_multiple_hunks)
24874                        .tooltip({
24875                            let focus_handle = editor.focus_handle(cx);
24876                            move |window, cx| {
24877                                Tooltip::for_action_in(
24878                                    "Previous Hunk",
24879                                    &GoToPreviousHunk,
24880                                    &focus_handle,
24881                                    window,
24882                                    cx,
24883                                )
24884                            }
24885                        })
24886                        .on_click({
24887                            let editor = editor.clone();
24888                            move |_event, window, cx| {
24889                                editor.update(cx, |editor, cx| {
24890                                    let snapshot = editor.snapshot(window, cx);
24891                                    let point =
24892                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24893                                    editor.go_to_hunk_before_or_after_position(
24894                                        &snapshot,
24895                                        point,
24896                                        Direction::Prev,
24897                                        window,
24898                                        cx,
24899                                    );
24900                                    editor.expand_selected_diff_hunks(cx);
24901                                });
24902                            }
24903                        }),
24904                )
24905            },
24906        )
24907        .into_any_element()
24908}
24909
24910pub fn multibuffer_context_lines(cx: &App) -> u32 {
24911    EditorSettings::try_get(cx)
24912        .map(|settings| settings.excerpt_context_lines)
24913        .unwrap_or(2)
24914        .min(32)
24915}