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<usize>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<usize>, 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    refresh_colors_task: Task<()>,
 1194    folding_newlines: Task<()>,
 1195    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1196}
 1197
 1198#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1199enum NextScrollCursorCenterTopBottom {
 1200    #[default]
 1201    Center,
 1202    Top,
 1203    Bottom,
 1204}
 1205
 1206impl NextScrollCursorCenterTopBottom {
 1207    fn next(&self) -> Self {
 1208        match self {
 1209            Self::Center => Self::Top,
 1210            Self::Top => Self::Bottom,
 1211            Self::Bottom => Self::Center,
 1212        }
 1213    }
 1214}
 1215
 1216#[derive(Clone)]
 1217pub struct EditorSnapshot {
 1218    pub mode: EditorMode,
 1219    show_gutter: bool,
 1220    show_line_numbers: Option<bool>,
 1221    show_git_diff_gutter: Option<bool>,
 1222    show_code_actions: Option<bool>,
 1223    show_runnables: Option<bool>,
 1224    show_breakpoints: Option<bool>,
 1225    git_blame_gutter_max_author_length: Option<usize>,
 1226    pub display_snapshot: DisplaySnapshot,
 1227    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1228    is_focused: bool,
 1229    scroll_anchor: ScrollAnchor,
 1230    ongoing_scroll: OngoingScroll,
 1231    current_line_highlight: CurrentLineHighlight,
 1232    gutter_hovered: bool,
 1233}
 1234
 1235#[derive(Default, Debug, Clone, Copy)]
 1236pub struct GutterDimensions {
 1237    pub left_padding: Pixels,
 1238    pub right_padding: Pixels,
 1239    pub width: Pixels,
 1240    pub margin: Pixels,
 1241    pub git_blame_entries_width: Option<Pixels>,
 1242}
 1243
 1244impl GutterDimensions {
 1245    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1246        Self {
 1247            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1248            ..Default::default()
 1249        }
 1250    }
 1251
 1252    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1253        -cx.text_system().descent(font_id, font_size)
 1254    }
 1255    /// The full width of the space taken up by the gutter.
 1256    pub fn full_width(&self) -> Pixels {
 1257        self.margin + self.width
 1258    }
 1259
 1260    /// The width of the space reserved for the fold indicators,
 1261    /// use alongside 'justify_end' and `gutter_width` to
 1262    /// right align content with the line numbers
 1263    pub fn fold_area_width(&self) -> Pixels {
 1264        self.margin + self.right_padding
 1265    }
 1266}
 1267
 1268struct CharacterDimensions {
 1269    em_width: Pixels,
 1270    em_advance: Pixels,
 1271    line_height: Pixels,
 1272}
 1273
 1274#[derive(Debug)]
 1275pub struct RemoteSelection {
 1276    pub replica_id: ReplicaId,
 1277    pub selection: Selection<Anchor>,
 1278    pub cursor_shape: CursorShape,
 1279    pub collaborator_id: CollaboratorId,
 1280    pub line_mode: bool,
 1281    pub user_name: Option<SharedString>,
 1282    pub color: PlayerColor,
 1283}
 1284
 1285#[derive(Clone, Debug)]
 1286struct SelectionHistoryEntry {
 1287    selections: Arc<[Selection<Anchor>]>,
 1288    select_next_state: Option<SelectNextState>,
 1289    select_prev_state: Option<SelectNextState>,
 1290    add_selections_state: Option<AddSelectionsState>,
 1291}
 1292
 1293#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1294enum SelectionHistoryMode {
 1295    Normal,
 1296    Undoing,
 1297    Redoing,
 1298    Skipping,
 1299}
 1300
 1301#[derive(Clone, PartialEq, Eq, Hash)]
 1302struct HoveredCursor {
 1303    replica_id: u16,
 1304    selection_id: usize,
 1305}
 1306
 1307impl Default for SelectionHistoryMode {
 1308    fn default() -> Self {
 1309        Self::Normal
 1310    }
 1311}
 1312
 1313#[derive(Debug)]
 1314/// SelectionEffects controls the side-effects of updating the selection.
 1315///
 1316/// The default behaviour does "what you mostly want":
 1317/// - it pushes to the nav history if the cursor moved by >10 lines
 1318/// - it re-triggers completion requests
 1319/// - it scrolls to fit
 1320///
 1321/// You might want to modify these behaviours. For example when doing a "jump"
 1322/// like go to definition, we always want to add to nav history; but when scrolling
 1323/// in vim mode we never do.
 1324///
 1325/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1326/// move.
 1327#[derive(Clone)]
 1328pub struct SelectionEffects {
 1329    nav_history: Option<bool>,
 1330    completions: bool,
 1331    scroll: Option<Autoscroll>,
 1332}
 1333
 1334impl Default for SelectionEffects {
 1335    fn default() -> Self {
 1336        Self {
 1337            nav_history: None,
 1338            completions: true,
 1339            scroll: Some(Autoscroll::fit()),
 1340        }
 1341    }
 1342}
 1343impl SelectionEffects {
 1344    pub fn scroll(scroll: Autoscroll) -> Self {
 1345        Self {
 1346            scroll: Some(scroll),
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn no_scroll() -> Self {
 1352        Self {
 1353            scroll: None,
 1354            ..Default::default()
 1355        }
 1356    }
 1357
 1358    pub fn completions(self, completions: bool) -> Self {
 1359        Self {
 1360            completions,
 1361            ..self
 1362        }
 1363    }
 1364
 1365    pub fn nav_history(self, nav_history: bool) -> Self {
 1366        Self {
 1367            nav_history: Some(nav_history),
 1368            ..self
 1369        }
 1370    }
 1371}
 1372
 1373struct DeferredSelectionEffectsState {
 1374    changed: bool,
 1375    effects: SelectionEffects,
 1376    old_cursor_position: Anchor,
 1377    history_entry: SelectionHistoryEntry,
 1378}
 1379
 1380#[derive(Default)]
 1381struct SelectionHistory {
 1382    #[allow(clippy::type_complexity)]
 1383    selections_by_transaction:
 1384        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1385    mode: SelectionHistoryMode,
 1386    undo_stack: VecDeque<SelectionHistoryEntry>,
 1387    redo_stack: VecDeque<SelectionHistoryEntry>,
 1388}
 1389
 1390impl SelectionHistory {
 1391    #[track_caller]
 1392    fn insert_transaction(
 1393        &mut self,
 1394        transaction_id: TransactionId,
 1395        selections: Arc<[Selection<Anchor>]>,
 1396    ) {
 1397        if selections.is_empty() {
 1398            log::error!(
 1399                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1400                std::panic::Location::caller()
 1401            );
 1402            return;
 1403        }
 1404        self.selections_by_transaction
 1405            .insert(transaction_id, (selections, None));
 1406    }
 1407
 1408    #[allow(clippy::type_complexity)]
 1409    fn transaction(
 1410        &self,
 1411        transaction_id: TransactionId,
 1412    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1413        self.selections_by_transaction.get(&transaction_id)
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction_mut(
 1418        &mut self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get_mut(&transaction_id)
 1422    }
 1423
 1424    fn push(&mut self, entry: SelectionHistoryEntry) {
 1425        if !entry.selections.is_empty() {
 1426            match self.mode {
 1427                SelectionHistoryMode::Normal => {
 1428                    self.push_undo(entry);
 1429                    self.redo_stack.clear();
 1430                }
 1431                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1432                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1433                SelectionHistoryMode::Skipping => {}
 1434            }
 1435        }
 1436    }
 1437
 1438    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1439        if self
 1440            .undo_stack
 1441            .back()
 1442            .is_none_or(|e| e.selections != entry.selections)
 1443        {
 1444            self.undo_stack.push_back(entry);
 1445            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1446                self.undo_stack.pop_front();
 1447            }
 1448        }
 1449    }
 1450
 1451    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1452        if self
 1453            .redo_stack
 1454            .back()
 1455            .is_none_or(|e| e.selections != entry.selections)
 1456        {
 1457            self.redo_stack.push_back(entry);
 1458            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1459                self.redo_stack.pop_front();
 1460            }
 1461        }
 1462    }
 1463}
 1464
 1465#[derive(Clone, Copy)]
 1466pub struct RowHighlightOptions {
 1467    pub autoscroll: bool,
 1468    pub include_gutter: bool,
 1469}
 1470
 1471impl Default for RowHighlightOptions {
 1472    fn default() -> Self {
 1473        Self {
 1474            autoscroll: Default::default(),
 1475            include_gutter: true,
 1476        }
 1477    }
 1478}
 1479
 1480struct RowHighlight {
 1481    index: usize,
 1482    range: Range<Anchor>,
 1483    color: Hsla,
 1484    options: RowHighlightOptions,
 1485    type_id: TypeId,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsState {
 1490    groups: Vec<AddSelectionsGroup>,
 1491}
 1492
 1493#[derive(Clone, Debug)]
 1494struct AddSelectionsGroup {
 1495    above: bool,
 1496    stack: Vec<usize>,
 1497}
 1498
 1499#[derive(Clone)]
 1500struct SelectNextState {
 1501    query: AhoCorasick,
 1502    wordwise: bool,
 1503    done: bool,
 1504}
 1505
 1506impl std::fmt::Debug for SelectNextState {
 1507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1508        f.debug_struct(std::any::type_name::<Self>())
 1509            .field("wordwise", &self.wordwise)
 1510            .field("done", &self.done)
 1511            .finish()
 1512    }
 1513}
 1514
 1515#[derive(Debug)]
 1516struct AutocloseRegion {
 1517    selection_id: usize,
 1518    range: Range<Anchor>,
 1519    pair: BracketPair,
 1520}
 1521
 1522#[derive(Debug)]
 1523struct SnippetState {
 1524    ranges: Vec<Vec<Range<Anchor>>>,
 1525    active_index: usize,
 1526    choices: Vec<Option<Vec<String>>>,
 1527}
 1528
 1529#[doc(hidden)]
 1530pub struct RenameState {
 1531    pub range: Range<Anchor>,
 1532    pub old_name: Arc<str>,
 1533    pub editor: Entity<Editor>,
 1534    block_id: CustomBlockId,
 1535}
 1536
 1537struct InvalidationStack<T>(Vec<T>);
 1538
 1539struct RegisteredEditPredictionProvider {
 1540    provider: Arc<dyn EditPredictionProviderHandle>,
 1541    _subscription: Subscription,
 1542}
 1543
 1544#[derive(Debug, PartialEq, Eq)]
 1545pub struct ActiveDiagnosticGroup {
 1546    pub active_range: Range<Anchor>,
 1547    pub active_message: String,
 1548    pub group_id: usize,
 1549    pub blocks: HashSet<CustomBlockId>,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553
 1554pub(crate) enum ActiveDiagnostic {
 1555    None,
 1556    All,
 1557    Group(ActiveDiagnosticGroup),
 1558}
 1559
 1560#[derive(Serialize, Deserialize, Clone, Debug)]
 1561pub struct ClipboardSelection {
 1562    /// The number of bytes in this selection.
 1563    pub len: usize,
 1564    /// Whether this was a full-line selection.
 1565    pub is_entire_line: bool,
 1566    /// The indentation of the first line when this content was originally copied.
 1567    pub first_line_indent: u32,
 1568}
 1569
 1570// selections, scroll behavior, was newest selection reversed
 1571type SelectSyntaxNodeHistoryState = (
 1572    Box<[Selection<usize>]>,
 1573    SelectSyntaxNodeScrollBehavior,
 1574    bool,
 1575);
 1576
 1577#[derive(Default)]
 1578struct SelectSyntaxNodeHistory {
 1579    stack: Vec<SelectSyntaxNodeHistoryState>,
 1580    // disable temporarily to allow changing selections without losing the stack
 1581    pub disable_clearing: bool,
 1582}
 1583
 1584impl SelectSyntaxNodeHistory {
 1585    pub fn try_clear(&mut self) {
 1586        if !self.disable_clearing {
 1587            self.stack.clear();
 1588        }
 1589    }
 1590
 1591    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1592        self.stack.push(selection);
 1593    }
 1594
 1595    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1596        self.stack.pop()
 1597    }
 1598}
 1599
 1600enum SelectSyntaxNodeScrollBehavior {
 1601    CursorTop,
 1602    FitSelection,
 1603    CursorBottom,
 1604}
 1605
 1606#[derive(Debug)]
 1607pub(crate) struct NavigationData {
 1608    cursor_anchor: Anchor,
 1609    cursor_position: Point,
 1610    scroll_anchor: ScrollAnchor,
 1611    scroll_top_row: u32,
 1612}
 1613
 1614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1615pub enum GotoDefinitionKind {
 1616    Symbol,
 1617    Declaration,
 1618    Type,
 1619    Implementation,
 1620}
 1621
 1622#[derive(Debug, Clone)]
 1623enum InlayHintRefreshReason {
 1624    ModifiersChanged(bool),
 1625    Toggle(bool),
 1626    SettingsChange(InlayHintSettings),
 1627    NewLinesShown,
 1628    BufferEdited(HashSet<Arc<Language>>),
 1629    RefreshRequested,
 1630    ExcerptsRemoved(Vec<ExcerptId>),
 1631}
 1632
 1633impl InlayHintRefreshReason {
 1634    fn description(&self) -> &'static str {
 1635        match self {
 1636            Self::ModifiersChanged(_) => "modifiers changed",
 1637            Self::Toggle(_) => "toggle",
 1638            Self::SettingsChange(_) => "settings change",
 1639            Self::NewLinesShown => "new lines shown",
 1640            Self::BufferEdited(_) => "buffer edited",
 1641            Self::RefreshRequested => "refresh requested",
 1642            Self::ExcerptsRemoved(_) => "excerpts removed",
 1643        }
 1644    }
 1645}
 1646
 1647pub enum FormatTarget {
 1648    Buffers(HashSet<Entity<Buffer>>),
 1649    Ranges(Vec<Range<MultiBufferPoint>>),
 1650}
 1651
 1652pub(crate) struct FocusedBlock {
 1653    id: BlockId,
 1654    focus_handle: WeakFocusHandle,
 1655}
 1656
 1657#[derive(Clone)]
 1658enum JumpData {
 1659    MultiBufferRow {
 1660        row: MultiBufferRow,
 1661        line_offset_from_top: u32,
 1662    },
 1663    MultiBufferPoint {
 1664        excerpt_id: ExcerptId,
 1665        position: Point,
 1666        anchor: text::Anchor,
 1667        line_offset_from_top: u32,
 1668    },
 1669}
 1670
 1671pub enum MultibufferSelectionMode {
 1672    First,
 1673    All,
 1674}
 1675
 1676#[derive(Clone, Copy, Debug, Default)]
 1677pub struct RewrapOptions {
 1678    pub override_language_settings: bool,
 1679    pub preserve_existing_whitespace: bool,
 1680}
 1681
 1682impl Editor {
 1683    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1687    }
 1688
 1689    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1690        let buffer = cx.new(|cx| Buffer::local("", cx));
 1691        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1692        Self::new(EditorMode::full(), buffer, None, window, cx)
 1693    }
 1694
 1695    pub fn auto_height(
 1696        min_lines: usize,
 1697        max_lines: usize,
 1698        window: &mut Window,
 1699        cx: &mut Context<Self>,
 1700    ) -> Self {
 1701        let buffer = cx.new(|cx| Buffer::local("", cx));
 1702        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1703        Self::new(
 1704            EditorMode::AutoHeight {
 1705                min_lines,
 1706                max_lines: Some(max_lines),
 1707            },
 1708            buffer,
 1709            None,
 1710            window,
 1711            cx,
 1712        )
 1713    }
 1714
 1715    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1716    /// The editor grows as tall as needed to fit its content.
 1717    pub fn auto_height_unbounded(
 1718        min_lines: usize,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| Buffer::local("", cx));
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(
 1725            EditorMode::AutoHeight {
 1726                min_lines,
 1727                max_lines: None,
 1728            },
 1729            buffer,
 1730            None,
 1731            window,
 1732            cx,
 1733        )
 1734    }
 1735
 1736    pub fn for_buffer(
 1737        buffer: Entity<Buffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1743        Self::new(EditorMode::full(), buffer, project, window, cx)
 1744    }
 1745
 1746    pub fn for_multibuffer(
 1747        buffer: Entity<MultiBuffer>,
 1748        project: Option<Entity<Project>>,
 1749        window: &mut Window,
 1750        cx: &mut Context<Self>,
 1751    ) -> Self {
 1752        Self::new(EditorMode::full(), buffer, project, window, cx)
 1753    }
 1754
 1755    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1756        let mut clone = Self::new(
 1757            self.mode.clone(),
 1758            self.buffer.clone(),
 1759            self.project.clone(),
 1760            window,
 1761            cx,
 1762        );
 1763        self.display_map.update(cx, |display_map, cx| {
 1764            let snapshot = display_map.snapshot(cx);
 1765            clone.display_map.update(cx, |display_map, cx| {
 1766                display_map.set_state(&snapshot, cx);
 1767            });
 1768        });
 1769        clone.folds_did_change(cx);
 1770        clone.selections.clone_state(&self.selections);
 1771        clone.scroll_manager.clone_state(&self.scroll_manager);
 1772        clone.searchable = self.searchable;
 1773        clone.read_only = self.read_only;
 1774        clone
 1775    }
 1776
 1777    pub fn new(
 1778        mode: EditorMode,
 1779        buffer: Entity<MultiBuffer>,
 1780        project: Option<Entity<Project>>,
 1781        window: &mut Window,
 1782        cx: &mut Context<Self>,
 1783    ) -> Self {
 1784        Editor::new_internal(mode, buffer, project, None, window, cx)
 1785    }
 1786
 1787    fn new_internal(
 1788        mode: EditorMode,
 1789        buffer: Entity<MultiBuffer>,
 1790        project: Option<Entity<Project>>,
 1791        display_map: Option<Entity<DisplayMap>>,
 1792        window: &mut Window,
 1793        cx: &mut Context<Self>,
 1794    ) -> Self {
 1795        debug_assert!(
 1796            display_map.is_none() || mode.is_minimap(),
 1797            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1798        );
 1799
 1800        let full_mode = mode.is_full();
 1801        let is_minimap = mode.is_minimap();
 1802        let diagnostics_max_severity = if full_mode {
 1803            EditorSettings::get_global(cx)
 1804                .diagnostics_max_severity
 1805                .unwrap_or(DiagnosticSeverity::Hint)
 1806        } else {
 1807            DiagnosticSeverity::Off
 1808        };
 1809        let style = window.text_style();
 1810        let font_size = style.font_size.to_pixels(window.rem_size());
 1811        let editor = cx.entity().downgrade();
 1812        let fold_placeholder = FoldPlaceholder {
 1813            constrain_width: false,
 1814            render: Arc::new(move |fold_id, fold_range, cx| {
 1815                let editor = editor.clone();
 1816                div()
 1817                    .id(fold_id)
 1818                    .bg(cx.theme().colors().ghost_element_background)
 1819                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1820                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1821                    .rounded_xs()
 1822                    .size_full()
 1823                    .cursor_pointer()
 1824                    .child("")
 1825                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1826                    .on_click(move |_, _window, cx| {
 1827                        editor
 1828                            .update(cx, |editor, cx| {
 1829                                editor.unfold_ranges(
 1830                                    &[fold_range.start..fold_range.end],
 1831                                    true,
 1832                                    false,
 1833                                    cx,
 1834                                );
 1835                                cx.stop_propagation();
 1836                            })
 1837                            .ok();
 1838                    })
 1839                    .into_any()
 1840            }),
 1841            merge_adjacent: true,
 1842            ..FoldPlaceholder::default()
 1843        };
 1844        let display_map = display_map.unwrap_or_else(|| {
 1845            cx.new(|cx| {
 1846                DisplayMap::new(
 1847                    buffer.clone(),
 1848                    style.font(),
 1849                    font_size,
 1850                    None,
 1851                    FILE_HEADER_HEIGHT,
 1852                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1853                    fold_placeholder,
 1854                    diagnostics_max_severity,
 1855                    cx,
 1856                )
 1857            })
 1858        });
 1859
 1860        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1861
 1862        let blink_manager = cx.new(|cx| {
 1863            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1864            if is_minimap {
 1865                blink_manager.disable(cx);
 1866            }
 1867            blink_manager
 1868        });
 1869
 1870        let soft_wrap_mode_override =
 1871            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1872
 1873        let mut project_subscriptions = Vec::new();
 1874        if full_mode && let Some(project) = project.as_ref() {
 1875            project_subscriptions.push(cx.subscribe_in(
 1876                project,
 1877                window,
 1878                |editor, _, event, window, cx| match event {
 1879                    project::Event::RefreshCodeLens => {
 1880                        // we always query lens with actions, without storing them, always refreshing them
 1881                    }
 1882                    project::Event::RefreshInlayHints => {
 1883                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1884                    }
 1885                    project::Event::LanguageServerAdded(..)
 1886                    | project::Event::LanguageServerRemoved(..) => {
 1887                        if editor.tasks_update_task.is_none() {
 1888                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1889                        }
 1890                    }
 1891                    project::Event::SnippetEdit(id, snippet_edits) => {
 1892                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1893                            let focus_handle = editor.focus_handle(cx);
 1894                            if focus_handle.is_focused(window) {
 1895                                let snapshot = buffer.read(cx).snapshot();
 1896                                for (range, snippet) in snippet_edits {
 1897                                    let editor_range =
 1898                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1899                                    editor
 1900                                        .insert_snippet(
 1901                                            &[editor_range],
 1902                                            snippet.clone(),
 1903                                            window,
 1904                                            cx,
 1905                                        )
 1906                                        .ok();
 1907                                }
 1908                            }
 1909                        }
 1910                    }
 1911                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1912                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1913                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1914                        }
 1915                    }
 1916
 1917                    project::Event::EntryRenamed(transaction) => {
 1918                        let Some(workspace) = editor.workspace() else {
 1919                            return;
 1920                        };
 1921                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1922                        else {
 1923                            return;
 1924                        };
 1925                        if active_editor.entity_id() == cx.entity_id() {
 1926                            let edited_buffers_already_open = {
 1927                                let other_editors: Vec<Entity<Editor>> = workspace
 1928                                    .read(cx)
 1929                                    .panes()
 1930                                    .iter()
 1931                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1932                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1933                                    .collect();
 1934
 1935                                transaction.0.keys().all(|buffer| {
 1936                                    other_editors.iter().any(|editor| {
 1937                                        let multi_buffer = editor.read(cx).buffer();
 1938                                        multi_buffer.read(cx).is_singleton()
 1939                                            && multi_buffer.read(cx).as_singleton().map_or(
 1940                                                false,
 1941                                                |singleton| {
 1942                                                    singleton.entity_id() == buffer.entity_id()
 1943                                                },
 1944                                            )
 1945                                    })
 1946                                })
 1947                            };
 1948
 1949                            if !edited_buffers_already_open {
 1950                                let workspace = workspace.downgrade();
 1951                                let transaction = transaction.clone();
 1952                                cx.defer_in(window, move |_, window, cx| {
 1953                                    cx.spawn_in(window, async move |editor, cx| {
 1954                                        Self::open_project_transaction(
 1955                                            &editor,
 1956                                            workspace,
 1957                                            transaction,
 1958                                            "Rename".to_string(),
 1959                                            cx,
 1960                                        )
 1961                                        .await
 1962                                        .ok()
 1963                                    })
 1964                                    .detach();
 1965                                });
 1966                            }
 1967                        }
 1968                    }
 1969
 1970                    _ => {}
 1971                },
 1972            ));
 1973            if let Some(task_inventory) = project
 1974                .read(cx)
 1975                .task_store()
 1976                .read(cx)
 1977                .task_inventory()
 1978                .cloned()
 1979            {
 1980                project_subscriptions.push(cx.observe_in(
 1981                    &task_inventory,
 1982                    window,
 1983                    |editor, _, window, cx| {
 1984                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1985                    },
 1986                ));
 1987            };
 1988
 1989            project_subscriptions.push(cx.subscribe_in(
 1990                &project.read(cx).breakpoint_store(),
 1991                window,
 1992                |editor, _, event, window, cx| match event {
 1993                    BreakpointStoreEvent::ClearDebugLines => {
 1994                        editor.clear_row_highlights::<ActiveDebugLine>();
 1995                        editor.refresh_inline_values(cx);
 1996                    }
 1997                    BreakpointStoreEvent::SetDebugLine => {
 1998                        if editor.go_to_active_debug_line(window, cx) {
 1999                            cx.stop_propagation();
 2000                        }
 2001
 2002                        editor.refresh_inline_values(cx);
 2003                    }
 2004                    _ => {}
 2005                },
 2006            ));
 2007            let git_store = project.read(cx).git_store().clone();
 2008            let project = project.clone();
 2009            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2010                if let GitStoreEvent::RepositoryUpdated(
 2011                    _,
 2012                    RepositoryEvent::Updated {
 2013                        new_instance: true, ..
 2014                    },
 2015                    _,
 2016                ) = event
 2017                {
 2018                    this.load_diff_task = Some(
 2019                        update_uncommitted_diff_for_buffer(
 2020                            cx.entity(),
 2021                            &project,
 2022                            this.buffer.read(cx).all_buffers(),
 2023                            this.buffer.clone(),
 2024                            cx,
 2025                        )
 2026                        .shared(),
 2027                    );
 2028                }
 2029            }));
 2030        }
 2031
 2032        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2033
 2034        let inlay_hint_settings =
 2035            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2036        let focus_handle = cx.focus_handle();
 2037        if !is_minimap {
 2038            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2039                .detach();
 2040            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2041                .detach();
 2042            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2043                .detach();
 2044            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2045                .detach();
 2046            cx.observe_pending_input(window, Self::observe_pending_input)
 2047                .detach();
 2048        }
 2049
 2050        let show_indent_guides =
 2051            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2052                Some(false)
 2053            } else {
 2054                None
 2055            };
 2056
 2057        let breakpoint_store = match (&mode, project.as_ref()) {
 2058            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2059            _ => None,
 2060        };
 2061
 2062        let mut code_action_providers = Vec::new();
 2063        let mut load_uncommitted_diff = None;
 2064        if let Some(project) = project.clone() {
 2065            load_uncommitted_diff = Some(
 2066                update_uncommitted_diff_for_buffer(
 2067                    cx.entity(),
 2068                    &project,
 2069                    buffer.read(cx).all_buffers(),
 2070                    buffer.clone(),
 2071                    cx,
 2072                )
 2073                .shared(),
 2074            );
 2075            code_action_providers.push(Rc::new(project) as Rc<_>);
 2076        }
 2077
 2078        let mut editor = Self {
 2079            focus_handle,
 2080            show_cursor_when_unfocused: false,
 2081            last_focused_descendant: None,
 2082            buffer: buffer.clone(),
 2083            display_map: display_map.clone(),
 2084            placeholder_display_map: None,
 2085            selections,
 2086            scroll_manager: ScrollManager::new(cx),
 2087            columnar_selection_state: None,
 2088            add_selections_state: None,
 2089            select_next_state: None,
 2090            select_prev_state: None,
 2091            selection_history: SelectionHistory::default(),
 2092            defer_selection_effects: false,
 2093            deferred_selection_effects_state: None,
 2094            autoclose_regions: Vec::new(),
 2095            snippet_stack: InvalidationStack::default(),
 2096            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2097            ime_transaction: None,
 2098            active_diagnostics: ActiveDiagnostic::None,
 2099            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2100            inline_diagnostics_update: Task::ready(()),
 2101            inline_diagnostics: Vec::new(),
 2102            soft_wrap_mode_override,
 2103            diagnostics_max_severity,
 2104            hard_wrap: None,
 2105            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2106            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2107            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2108            project,
 2109            blink_manager: blink_manager.clone(),
 2110            show_local_selections: true,
 2111            show_scrollbars: ScrollbarAxes {
 2112                horizontal: full_mode,
 2113                vertical: full_mode,
 2114            },
 2115            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2116            offset_content: !matches!(mode, EditorMode::SingleLine),
 2117            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2118            show_gutter: full_mode,
 2119            show_line_numbers: (!full_mode).then_some(false),
 2120            use_relative_line_numbers: None,
 2121            disable_expand_excerpt_buttons: !full_mode,
 2122            show_git_diff_gutter: None,
 2123            show_code_actions: None,
 2124            show_runnables: None,
 2125            show_breakpoints: None,
 2126            show_wrap_guides: None,
 2127            show_indent_guides,
 2128            highlight_order: 0,
 2129            highlighted_rows: HashMap::default(),
 2130            background_highlights: HashMap::default(),
 2131            gutter_highlights: HashMap::default(),
 2132            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2133            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2134            nav_history: None,
 2135            context_menu: RefCell::new(None),
 2136            context_menu_options: None,
 2137            mouse_context_menu: None,
 2138            completion_tasks: Vec::new(),
 2139            inline_blame_popover: None,
 2140            inline_blame_popover_show_task: None,
 2141            signature_help_state: SignatureHelpState::default(),
 2142            auto_signature_help: None,
 2143            find_all_references_task_sources: Vec::new(),
 2144            next_completion_id: 0,
 2145            next_inlay_id: 0,
 2146            code_action_providers,
 2147            available_code_actions: None,
 2148            code_actions_task: None,
 2149            quick_selection_highlight_task: None,
 2150            debounced_selection_highlight_task: None,
 2151            document_highlights_task: None,
 2152            linked_editing_range_task: None,
 2153            pending_rename: None,
 2154            searchable: !is_minimap,
 2155            cursor_shape: EditorSettings::get_global(cx)
 2156                .cursor_shape
 2157                .unwrap_or_default(),
 2158            current_line_highlight: None,
 2159            autoindent_mode: Some(AutoindentMode::EachLine),
 2160            collapse_matches: false,
 2161            workspace: None,
 2162            input_enabled: !is_minimap,
 2163            use_modal_editing: full_mode,
 2164            read_only: is_minimap,
 2165            use_autoclose: true,
 2166            use_auto_surround: true,
 2167            auto_replace_emoji_shortcode: false,
 2168            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2169            leader_id: None,
 2170            remote_id: None,
 2171            hover_state: HoverState::default(),
 2172            pending_mouse_down: None,
 2173            hovered_link_state: None,
 2174            edit_prediction_provider: None,
 2175            active_edit_prediction: None,
 2176            stale_edit_prediction_in_menu: None,
 2177            edit_prediction_preview: EditPredictionPreview::Inactive {
 2178                released_too_fast: false,
 2179            },
 2180            inline_diagnostics_enabled: full_mode,
 2181            diagnostics_enabled: full_mode,
 2182            word_completions_enabled: full_mode,
 2183            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2184            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2185            gutter_hovered: false,
 2186            pixel_position_of_newest_cursor: None,
 2187            last_bounds: None,
 2188            last_position_map: None,
 2189            expect_bounds_change: None,
 2190            gutter_dimensions: GutterDimensions::default(),
 2191            style: None,
 2192            show_cursor_names: false,
 2193            hovered_cursors: HashMap::default(),
 2194            next_editor_action_id: EditorActionId::default(),
 2195            editor_actions: Rc::default(),
 2196            edit_predictions_hidden_for_vim_mode: false,
 2197            show_edit_predictions_override: None,
 2198            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2199            edit_prediction_settings: EditPredictionSettings::Disabled,
 2200            edit_prediction_indent_conflict: false,
 2201            edit_prediction_requires_modifier_in_indent_conflict: true,
 2202            custom_context_menu: None,
 2203            show_git_blame_gutter: false,
 2204            show_git_blame_inline: false,
 2205            show_selection_menu: None,
 2206            show_git_blame_inline_delay_task: None,
 2207            git_blame_inline_enabled: full_mode
 2208                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2209            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2210            serialize_dirty_buffers: !is_minimap
 2211                && ProjectSettings::get_global(cx)
 2212                    .session
 2213                    .restore_unsaved_buffers,
 2214            blame: None,
 2215            blame_subscription: None,
 2216            tasks: BTreeMap::default(),
 2217
 2218            breakpoint_store,
 2219            gutter_breakpoint_indicator: (None, None),
 2220            hovered_diff_hunk_row: None,
 2221            _subscriptions: (!is_minimap)
 2222                .then(|| {
 2223                    vec![
 2224                        cx.observe(&buffer, Self::on_buffer_changed),
 2225                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2226                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2227                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2228                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2229                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2230                        cx.observe_window_activation(window, |editor, window, cx| {
 2231                            let active = window.is_window_active();
 2232                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2233                                if active {
 2234                                    blink_manager.enable(cx);
 2235                                } else {
 2236                                    blink_manager.disable(cx);
 2237                                }
 2238                            });
 2239                            if active {
 2240                                editor.show_mouse_cursor(cx);
 2241                            }
 2242                        }),
 2243                    ]
 2244                })
 2245                .unwrap_or_default(),
 2246            tasks_update_task: None,
 2247            pull_diagnostics_task: Task::ready(()),
 2248            colors: None,
 2249            refresh_colors_task: Task::ready(()),
 2250            next_color_inlay_id: 0,
 2251            linked_edit_ranges: Default::default(),
 2252            in_project_search: false,
 2253            previous_search_ranges: None,
 2254            breadcrumb_header: None,
 2255            focused_block: None,
 2256            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2257            addons: HashMap::default(),
 2258            registered_buffers: HashMap::default(),
 2259            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2260            selection_mark_mode: false,
 2261            toggle_fold_multiple_buffers: Task::ready(()),
 2262            serialize_selections: Task::ready(()),
 2263            serialize_folds: Task::ready(()),
 2264            text_style_refinement: None,
 2265            load_diff_task: load_uncommitted_diff,
 2266            temporary_diff_override: false,
 2267            mouse_cursor_hidden: false,
 2268            minimap: None,
 2269            hide_mouse_mode: EditorSettings::get_global(cx)
 2270                .hide_mouse
 2271                .unwrap_or_default(),
 2272            change_list: ChangeList::new(),
 2273            mode,
 2274            selection_drag_state: SelectionDragState::None,
 2275            folding_newlines: Task::ready(()),
 2276            lookup_key: None,
 2277        };
 2278
 2279        if is_minimap {
 2280            return editor;
 2281        }
 2282
 2283        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2284            editor
 2285                ._subscriptions
 2286                .push(cx.observe(breakpoints, |_, _, cx| {
 2287                    cx.notify();
 2288                }));
 2289        }
 2290        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2291        editor._subscriptions.extend(project_subscriptions);
 2292
 2293        editor._subscriptions.push(cx.subscribe_in(
 2294            &cx.entity(),
 2295            window,
 2296            |editor, _, e: &EditorEvent, window, cx| match e {
 2297                EditorEvent::ScrollPositionChanged { local, .. } => {
 2298                    if *local {
 2299                        let new_anchor = editor.scroll_manager.anchor();
 2300                        let snapshot = editor.snapshot(window, cx);
 2301                        editor.update_restoration_data(cx, move |data| {
 2302                            data.scroll_position = (
 2303                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2304                                new_anchor.offset,
 2305                            );
 2306                        });
 2307                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2308                        editor.inline_blame_popover.take();
 2309                    }
 2310                }
 2311                EditorEvent::Edited { .. } => {
 2312                    if !vim_enabled(cx) {
 2313                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2314                        let pop_state = editor
 2315                            .change_list
 2316                            .last()
 2317                            .map(|previous| {
 2318                                previous.len() == selections.len()
 2319                                    && previous.iter().enumerate().all(|(ix, p)| {
 2320                                        p.to_display_point(&map).row()
 2321                                            == selections[ix].head().row()
 2322                                    })
 2323                            })
 2324                            .unwrap_or(false);
 2325                        let new_positions = selections
 2326                            .into_iter()
 2327                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2328                            .collect();
 2329                        editor
 2330                            .change_list
 2331                            .push_to_change_list(pop_state, new_positions);
 2332                    }
 2333                }
 2334                _ => (),
 2335            },
 2336        ));
 2337
 2338        if let Some(dap_store) = editor
 2339            .project
 2340            .as_ref()
 2341            .map(|project| project.read(cx).dap_store())
 2342        {
 2343            let weak_editor = cx.weak_entity();
 2344
 2345            editor
 2346                ._subscriptions
 2347                .push(
 2348                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2349                        let session_entity = cx.entity();
 2350                        weak_editor
 2351                            .update(cx, |editor, cx| {
 2352                                editor._subscriptions.push(
 2353                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2354                                );
 2355                            })
 2356                            .ok();
 2357                    }),
 2358                );
 2359
 2360            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2361                editor
 2362                    ._subscriptions
 2363                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2364            }
 2365        }
 2366
 2367        // skip adding the initial selection to selection history
 2368        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2369        editor.end_selection(window, cx);
 2370        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2371
 2372        editor.scroll_manager.show_scrollbars(window, cx);
 2373        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2374
 2375        if full_mode {
 2376            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2377            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2378
 2379            if editor.git_blame_inline_enabled {
 2380                editor.start_git_blame_inline(false, window, cx);
 2381            }
 2382
 2383            editor.go_to_active_debug_line(window, cx);
 2384
 2385            if let Some(buffer) = buffer.read(cx).as_singleton()
 2386                && let Some(project) = editor.project()
 2387            {
 2388                let handle = project.update(cx, |project, cx| {
 2389                    project.register_buffer_with_language_servers(&buffer, cx)
 2390                });
 2391                editor
 2392                    .registered_buffers
 2393                    .insert(buffer.read(cx).remote_id(), handle);
 2394            }
 2395
 2396            editor.minimap =
 2397                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2398            editor.colors = Some(LspColorData::new(cx));
 2399            editor.update_lsp_data(false, None, window, cx);
 2400        }
 2401
 2402        if editor.mode.is_full() {
 2403            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2404        }
 2405
 2406        editor
 2407    }
 2408
 2409    pub fn deploy_mouse_context_menu(
 2410        &mut self,
 2411        position: gpui::Point<Pixels>,
 2412        context_menu: Entity<ContextMenu>,
 2413        window: &mut Window,
 2414        cx: &mut Context<Self>,
 2415    ) {
 2416        self.mouse_context_menu = Some(MouseContextMenu::new(
 2417            self,
 2418            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2419            context_menu,
 2420            window,
 2421            cx,
 2422        ));
 2423    }
 2424
 2425    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2426        self.mouse_context_menu
 2427            .as_ref()
 2428            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2429    }
 2430
 2431    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2432        if self
 2433            .selections
 2434            .pending_anchor()
 2435            .is_some_and(|pending_selection| {
 2436                let snapshot = self.buffer().read(cx).snapshot(cx);
 2437                pending_selection.range().includes(range, &snapshot)
 2438            })
 2439        {
 2440            return true;
 2441        }
 2442
 2443        self.selections
 2444            .disjoint_in_range::<usize>(range.clone(), cx)
 2445            .into_iter()
 2446            .any(|selection| {
 2447                // This is needed to cover a corner case, if we just check for an existing
 2448                // selection in the fold range, having a cursor at the start of the fold
 2449                // marks it as selected. Non-empty selections don't cause this.
 2450                let length = selection.end - selection.start;
 2451                length > 0
 2452            })
 2453    }
 2454
 2455    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2456        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2457    }
 2458
 2459    fn key_context_internal(
 2460        &self,
 2461        has_active_edit_prediction: bool,
 2462        window: &Window,
 2463        cx: &App,
 2464    ) -> KeyContext {
 2465        let mut key_context = KeyContext::new_with_defaults();
 2466        key_context.add("Editor");
 2467        let mode = match self.mode {
 2468            EditorMode::SingleLine => "single_line",
 2469            EditorMode::AutoHeight { .. } => "auto_height",
 2470            EditorMode::Minimap { .. } => "minimap",
 2471            EditorMode::Full { .. } => "full",
 2472        };
 2473
 2474        if EditorSettings::jupyter_enabled(cx) {
 2475            key_context.add("jupyter");
 2476        }
 2477
 2478        key_context.set("mode", mode);
 2479        if self.pending_rename.is_some() {
 2480            key_context.add("renaming");
 2481        }
 2482
 2483        match self.context_menu.borrow().as_ref() {
 2484            Some(CodeContextMenu::Completions(menu)) => {
 2485                if menu.visible() {
 2486                    key_context.add("menu");
 2487                    key_context.add("showing_completions");
 2488                }
 2489            }
 2490            Some(CodeContextMenu::CodeActions(menu)) => {
 2491                if menu.visible() {
 2492                    key_context.add("menu");
 2493                    key_context.add("showing_code_actions")
 2494                }
 2495            }
 2496            None => {}
 2497        }
 2498
 2499        if self.signature_help_state.has_multiple_signatures() {
 2500            key_context.add("showing_signature_help");
 2501        }
 2502
 2503        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2504        if !self.focus_handle(cx).contains_focused(window, cx)
 2505            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2506        {
 2507            for addon in self.addons.values() {
 2508                addon.extend_key_context(&mut key_context, cx)
 2509            }
 2510        }
 2511
 2512        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2513            if let Some(extension) = singleton_buffer
 2514                .read(cx)
 2515                .file()
 2516                .and_then(|file| file.path().extension())
 2517            {
 2518                key_context.set("extension", extension.to_string());
 2519            }
 2520        } else {
 2521            key_context.add("multibuffer");
 2522        }
 2523
 2524        if has_active_edit_prediction {
 2525            if self.edit_prediction_in_conflict() {
 2526                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2527            } else {
 2528                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2529                key_context.add("copilot_suggestion");
 2530            }
 2531        }
 2532
 2533        if self.selection_mark_mode {
 2534            key_context.add("selection_mode");
 2535        }
 2536
 2537        key_context
 2538    }
 2539
 2540    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2541        self.last_bounds.as_ref()
 2542    }
 2543
 2544    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2545        if self.mouse_cursor_hidden {
 2546            self.mouse_cursor_hidden = false;
 2547            cx.notify();
 2548        }
 2549    }
 2550
 2551    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2552        let hide_mouse_cursor = match origin {
 2553            HideMouseCursorOrigin::TypingAction => {
 2554                matches!(
 2555                    self.hide_mouse_mode,
 2556                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2557                )
 2558            }
 2559            HideMouseCursorOrigin::MovementAction => {
 2560                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2561            }
 2562        };
 2563        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2564            self.mouse_cursor_hidden = hide_mouse_cursor;
 2565            cx.notify();
 2566        }
 2567    }
 2568
 2569    pub fn edit_prediction_in_conflict(&self) -> bool {
 2570        if !self.show_edit_predictions_in_menu() {
 2571            return false;
 2572        }
 2573
 2574        let showing_completions = self
 2575            .context_menu
 2576            .borrow()
 2577            .as_ref()
 2578            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2579
 2580        showing_completions
 2581            || self.edit_prediction_requires_modifier()
 2582            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2583            // bindings to insert tab characters.
 2584            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2585    }
 2586
 2587    pub fn accept_edit_prediction_keybind(
 2588        &self,
 2589        accept_partial: bool,
 2590        window: &Window,
 2591        cx: &App,
 2592    ) -> AcceptEditPredictionBinding {
 2593        let key_context = self.key_context_internal(true, window, cx);
 2594        let in_conflict = self.edit_prediction_in_conflict();
 2595
 2596        let bindings = if accept_partial {
 2597            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2598        } else {
 2599            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2600        };
 2601
 2602        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2603        // just the first one.
 2604        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2605            !in_conflict
 2606                || binding
 2607                    .keystrokes()
 2608                    .first()
 2609                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2610        }))
 2611    }
 2612
 2613    pub fn new_file(
 2614        workspace: &mut Workspace,
 2615        _: &workspace::NewFile,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) {
 2619        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2620            "Failed to create buffer",
 2621            window,
 2622            cx,
 2623            |e, _, _| match e.error_code() {
 2624                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2625                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2626                e.error_tag("required").unwrap_or("the latest version")
 2627            )),
 2628                _ => None,
 2629            },
 2630        );
 2631    }
 2632
 2633    pub fn new_in_workspace(
 2634        workspace: &mut Workspace,
 2635        window: &mut Window,
 2636        cx: &mut Context<Workspace>,
 2637    ) -> Task<Result<Entity<Editor>>> {
 2638        let project = workspace.project().clone();
 2639        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2640
 2641        cx.spawn_in(window, async move |workspace, cx| {
 2642            let buffer = create.await?;
 2643            workspace.update_in(cx, |workspace, window, cx| {
 2644                let editor =
 2645                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2646                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2647                editor
 2648            })
 2649        })
 2650    }
 2651
 2652    fn new_file_vertical(
 2653        workspace: &mut Workspace,
 2654        _: &workspace::NewFileSplitVertical,
 2655        window: &mut Window,
 2656        cx: &mut Context<Workspace>,
 2657    ) {
 2658        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2659    }
 2660
 2661    fn new_file_horizontal(
 2662        workspace: &mut Workspace,
 2663        _: &workspace::NewFileSplitHorizontal,
 2664        window: &mut Window,
 2665        cx: &mut Context<Workspace>,
 2666    ) {
 2667        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2668    }
 2669
 2670    fn new_file_in_direction(
 2671        workspace: &mut Workspace,
 2672        direction: SplitDirection,
 2673        window: &mut Window,
 2674        cx: &mut Context<Workspace>,
 2675    ) {
 2676        let project = workspace.project().clone();
 2677        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2678
 2679        cx.spawn_in(window, async move |workspace, cx| {
 2680            let buffer = create.await?;
 2681            workspace.update_in(cx, move |workspace, window, cx| {
 2682                workspace.split_item(
 2683                    direction,
 2684                    Box::new(
 2685                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2686                    ),
 2687                    window,
 2688                    cx,
 2689                )
 2690            })?;
 2691            anyhow::Ok(())
 2692        })
 2693        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2694            match e.error_code() {
 2695                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2696                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2697                e.error_tag("required").unwrap_or("the latest version")
 2698            )),
 2699                _ => None,
 2700            }
 2701        });
 2702    }
 2703
 2704    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2705        self.leader_id
 2706    }
 2707
 2708    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2709        &self.buffer
 2710    }
 2711
 2712    pub fn project(&self) -> Option<&Entity<Project>> {
 2713        self.project.as_ref()
 2714    }
 2715
 2716    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2717        self.workspace.as_ref()?.0.upgrade()
 2718    }
 2719
 2720    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2721        self.buffer().read(cx).title(cx)
 2722    }
 2723
 2724    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2725        let git_blame_gutter_max_author_length = self
 2726            .render_git_blame_gutter(cx)
 2727            .then(|| {
 2728                if let Some(blame) = self.blame.as_ref() {
 2729                    let max_author_length =
 2730                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2731                    Some(max_author_length)
 2732                } else {
 2733                    None
 2734                }
 2735            })
 2736            .flatten();
 2737
 2738        EditorSnapshot {
 2739            mode: self.mode.clone(),
 2740            show_gutter: self.show_gutter,
 2741            show_line_numbers: self.show_line_numbers,
 2742            show_git_diff_gutter: self.show_git_diff_gutter,
 2743            show_code_actions: self.show_code_actions,
 2744            show_runnables: self.show_runnables,
 2745            show_breakpoints: self.show_breakpoints,
 2746            git_blame_gutter_max_author_length,
 2747            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2748            placeholder_display_snapshot: self
 2749                .placeholder_display_map
 2750                .as_ref()
 2751                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2752            scroll_anchor: self.scroll_manager.anchor(),
 2753            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2754            is_focused: self.focus_handle.is_focused(window),
 2755            current_line_highlight: self
 2756                .current_line_highlight
 2757                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2758            gutter_hovered: self.gutter_hovered,
 2759        }
 2760    }
 2761
 2762    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2763        self.buffer.read(cx).language_at(point, cx)
 2764    }
 2765
 2766    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2767        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2768    }
 2769
 2770    pub fn active_excerpt(
 2771        &self,
 2772        cx: &App,
 2773    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2774        self.buffer
 2775            .read(cx)
 2776            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2777    }
 2778
 2779    pub fn mode(&self) -> &EditorMode {
 2780        &self.mode
 2781    }
 2782
 2783    pub fn set_mode(&mut self, mode: EditorMode) {
 2784        self.mode = mode;
 2785    }
 2786
 2787    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2788        self.collaboration_hub.as_deref()
 2789    }
 2790
 2791    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2792        self.collaboration_hub = Some(hub);
 2793    }
 2794
 2795    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2796        self.in_project_search = in_project_search;
 2797    }
 2798
 2799    pub fn set_custom_context_menu(
 2800        &mut self,
 2801        f: impl 'static
 2802        + Fn(
 2803            &mut Self,
 2804            DisplayPoint,
 2805            &mut Window,
 2806            &mut Context<Self>,
 2807        ) -> Option<Entity<ui::ContextMenu>>,
 2808    ) {
 2809        self.custom_context_menu = Some(Box::new(f))
 2810    }
 2811
 2812    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2813        self.completion_provider = provider;
 2814    }
 2815
 2816    #[cfg(any(test, feature = "test-support"))]
 2817    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2818        self.completion_provider.clone()
 2819    }
 2820
 2821    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2822        self.semantics_provider.clone()
 2823    }
 2824
 2825    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2826        self.semantics_provider = provider;
 2827    }
 2828
 2829    pub fn set_edit_prediction_provider<T>(
 2830        &mut self,
 2831        provider: Option<Entity<T>>,
 2832        window: &mut Window,
 2833        cx: &mut Context<Self>,
 2834    ) where
 2835        T: EditPredictionProvider,
 2836    {
 2837        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2838            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2839                if this.focus_handle.is_focused(window) {
 2840                    this.update_visible_edit_prediction(window, cx);
 2841                }
 2842            }),
 2843            provider: Arc::new(provider),
 2844        });
 2845        self.update_edit_prediction_settings(cx);
 2846        self.refresh_edit_prediction(false, false, window, cx);
 2847    }
 2848
 2849    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2850        self.placeholder_display_map
 2851            .as_ref()
 2852            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2853    }
 2854
 2855    pub fn set_placeholder_text(
 2856        &mut self,
 2857        placeholder_text: &str,
 2858        window: &mut Window,
 2859        cx: &mut Context<Self>,
 2860    ) {
 2861        let multibuffer = cx
 2862            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2863
 2864        let style = window.text_style();
 2865
 2866        self.placeholder_display_map = Some(cx.new(|cx| {
 2867            DisplayMap::new(
 2868                multibuffer,
 2869                style.font(),
 2870                style.font_size.to_pixels(window.rem_size()),
 2871                None,
 2872                FILE_HEADER_HEIGHT,
 2873                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2874                Default::default(),
 2875                DiagnosticSeverity::Off,
 2876                cx,
 2877            )
 2878        }));
 2879        cx.notify();
 2880    }
 2881
 2882    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2883        self.cursor_shape = cursor_shape;
 2884
 2885        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2886        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2887
 2888        cx.notify();
 2889    }
 2890
 2891    pub fn set_current_line_highlight(
 2892        &mut self,
 2893        current_line_highlight: Option<CurrentLineHighlight>,
 2894    ) {
 2895        self.current_line_highlight = current_line_highlight;
 2896    }
 2897
 2898    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2899        self.collapse_matches = collapse_matches;
 2900    }
 2901
 2902    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2903        let buffers = self.buffer.read(cx).all_buffers();
 2904        let Some(project) = self.project.as_ref() else {
 2905            return;
 2906        };
 2907        project.update(cx, |project, cx| {
 2908            for buffer in buffers {
 2909                self.registered_buffers
 2910                    .entry(buffer.read(cx).remote_id())
 2911                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2912            }
 2913        })
 2914    }
 2915
 2916    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2917        if self.collapse_matches {
 2918            return range.start..range.start;
 2919        }
 2920        range.clone()
 2921    }
 2922
 2923    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2924        if self.display_map.read(cx).clip_at_line_ends != clip {
 2925            self.display_map
 2926                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2927        }
 2928    }
 2929
 2930    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2931        self.input_enabled = input_enabled;
 2932    }
 2933
 2934    pub fn set_edit_predictions_hidden_for_vim_mode(
 2935        &mut self,
 2936        hidden: bool,
 2937        window: &mut Window,
 2938        cx: &mut Context<Self>,
 2939    ) {
 2940        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2941            self.edit_predictions_hidden_for_vim_mode = hidden;
 2942            if hidden {
 2943                self.update_visible_edit_prediction(window, cx);
 2944            } else {
 2945                self.refresh_edit_prediction(true, false, window, cx);
 2946            }
 2947        }
 2948    }
 2949
 2950    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2951        self.menu_edit_predictions_policy = value;
 2952    }
 2953
 2954    pub fn set_autoindent(&mut self, autoindent: bool) {
 2955        if autoindent {
 2956            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2957        } else {
 2958            self.autoindent_mode = None;
 2959        }
 2960    }
 2961
 2962    pub fn read_only(&self, cx: &App) -> bool {
 2963        self.read_only || self.buffer.read(cx).read_only()
 2964    }
 2965
 2966    pub fn set_read_only(&mut self, read_only: bool) {
 2967        self.read_only = read_only;
 2968    }
 2969
 2970    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2971        self.use_autoclose = autoclose;
 2972    }
 2973
 2974    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2975        self.use_auto_surround = auto_surround;
 2976    }
 2977
 2978    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2979        self.auto_replace_emoji_shortcode = auto_replace;
 2980    }
 2981
 2982    pub fn toggle_edit_predictions(
 2983        &mut self,
 2984        _: &ToggleEditPrediction,
 2985        window: &mut Window,
 2986        cx: &mut Context<Self>,
 2987    ) {
 2988        if self.show_edit_predictions_override.is_some() {
 2989            self.set_show_edit_predictions(None, window, cx);
 2990        } else {
 2991            let show_edit_predictions = !self.edit_predictions_enabled();
 2992            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2993        }
 2994    }
 2995
 2996    pub fn set_show_edit_predictions(
 2997        &mut self,
 2998        show_edit_predictions: Option<bool>,
 2999        window: &mut Window,
 3000        cx: &mut Context<Self>,
 3001    ) {
 3002        self.show_edit_predictions_override = show_edit_predictions;
 3003        self.update_edit_prediction_settings(cx);
 3004
 3005        if let Some(false) = show_edit_predictions {
 3006            self.discard_edit_prediction(false, cx);
 3007        } else {
 3008            self.refresh_edit_prediction(false, true, window, cx);
 3009        }
 3010    }
 3011
 3012    fn edit_predictions_disabled_in_scope(
 3013        &self,
 3014        buffer: &Entity<Buffer>,
 3015        buffer_position: language::Anchor,
 3016        cx: &App,
 3017    ) -> bool {
 3018        let snapshot = buffer.read(cx).snapshot();
 3019        let settings = snapshot.settings_at(buffer_position, cx);
 3020
 3021        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3022            return false;
 3023        };
 3024
 3025        scope.override_name().is_some_and(|scope_name| {
 3026            settings
 3027                .edit_predictions_disabled_in
 3028                .iter()
 3029                .any(|s| s == scope_name)
 3030        })
 3031    }
 3032
 3033    pub fn set_use_modal_editing(&mut self, to: bool) {
 3034        self.use_modal_editing = to;
 3035    }
 3036
 3037    pub fn use_modal_editing(&self) -> bool {
 3038        self.use_modal_editing
 3039    }
 3040
 3041    fn selections_did_change(
 3042        &mut self,
 3043        local: bool,
 3044        old_cursor_position: &Anchor,
 3045        effects: SelectionEffects,
 3046        window: &mut Window,
 3047        cx: &mut Context<Self>,
 3048    ) {
 3049        window.invalidate_character_coordinates();
 3050
 3051        // Copy selections to primary selection buffer
 3052        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3053        if local {
 3054            let selections = self.selections.all::<usize>(cx);
 3055            let buffer_handle = self.buffer.read(cx).read(cx);
 3056
 3057            let mut text = String::new();
 3058            for (index, selection) in selections.iter().enumerate() {
 3059                let text_for_selection = buffer_handle
 3060                    .text_for_range(selection.start..selection.end)
 3061                    .collect::<String>();
 3062
 3063                text.push_str(&text_for_selection);
 3064                if index != selections.len() - 1 {
 3065                    text.push('\n');
 3066                }
 3067            }
 3068
 3069            if !text.is_empty() {
 3070                cx.write_to_primary(ClipboardItem::new_string(text));
 3071            }
 3072        }
 3073
 3074        let selection_anchors = self.selections.disjoint_anchors_arc();
 3075
 3076        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3077            self.buffer.update(cx, |buffer, cx| {
 3078                buffer.set_active_selections(
 3079                    &selection_anchors,
 3080                    self.selections.line_mode(),
 3081                    self.cursor_shape,
 3082                    cx,
 3083                )
 3084            });
 3085        }
 3086        let display_map = self
 3087            .display_map
 3088            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3089        let buffer = display_map.buffer_snapshot();
 3090        if self.selections.count() == 1 {
 3091            self.add_selections_state = None;
 3092        }
 3093        self.select_next_state = None;
 3094        self.select_prev_state = None;
 3095        self.select_syntax_node_history.try_clear();
 3096        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3097        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3098        self.take_rename(false, window, cx);
 3099
 3100        let newest_selection = self.selections.newest_anchor();
 3101        let new_cursor_position = newest_selection.head();
 3102        let selection_start = newest_selection.start;
 3103
 3104        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3105            self.push_to_nav_history(
 3106                *old_cursor_position,
 3107                Some(new_cursor_position.to_point(buffer)),
 3108                false,
 3109                effects.nav_history == Some(true),
 3110                cx,
 3111            );
 3112        }
 3113
 3114        if local {
 3115            if let Some(buffer_id) = new_cursor_position.buffer_id
 3116                && !self.registered_buffers.contains_key(&buffer_id)
 3117                && let Some(project) = self.project.as_ref()
 3118            {
 3119                project.update(cx, |project, cx| {
 3120                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3121                        return;
 3122                    };
 3123                    self.registered_buffers.insert(
 3124                        buffer_id,
 3125                        project.register_buffer_with_language_servers(&buffer, cx),
 3126                    );
 3127                })
 3128            }
 3129
 3130            let mut context_menu = self.context_menu.borrow_mut();
 3131            let completion_menu = match context_menu.as_ref() {
 3132                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3133                Some(CodeContextMenu::CodeActions(_)) => {
 3134                    *context_menu = None;
 3135                    None
 3136                }
 3137                None => None,
 3138            };
 3139            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3140            drop(context_menu);
 3141
 3142            if effects.completions
 3143                && let Some(completion_position) = completion_position
 3144            {
 3145                let start_offset = selection_start.to_offset(buffer);
 3146                let position_matches = start_offset == completion_position.to_offset(buffer);
 3147                let continue_showing = if position_matches {
 3148                    if self.snippet_stack.is_empty() {
 3149                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3150                            == Some(CharKind::Word)
 3151                    } else {
 3152                        // Snippet choices can be shown even when the cursor is in whitespace.
 3153                        // Dismissing the menu with actions like backspace is handled by
 3154                        // invalidation regions.
 3155                        true
 3156                    }
 3157                } else {
 3158                    false
 3159                };
 3160
 3161                if continue_showing {
 3162                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3163                } else {
 3164                    self.hide_context_menu(window, cx);
 3165                }
 3166            }
 3167
 3168            hide_hover(self, cx);
 3169
 3170            if old_cursor_position.to_display_point(&display_map).row()
 3171                != new_cursor_position.to_display_point(&display_map).row()
 3172            {
 3173                self.available_code_actions.take();
 3174            }
 3175            self.refresh_code_actions(window, cx);
 3176            self.refresh_document_highlights(cx);
 3177            self.refresh_selected_text_highlights(false, window, cx);
 3178            refresh_matching_bracket_highlights(self, cx);
 3179            self.update_visible_edit_prediction(window, cx);
 3180            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3181            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3182            self.inline_blame_popover.take();
 3183            if self.git_blame_inline_enabled {
 3184                self.start_inline_blame_timer(window, cx);
 3185            }
 3186        }
 3187
 3188        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3189        cx.emit(EditorEvent::SelectionsChanged { local });
 3190
 3191        let selections = &self.selections.disjoint_anchors_arc();
 3192        if selections.len() == 1 {
 3193            cx.emit(SearchEvent::ActiveMatchChanged)
 3194        }
 3195        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3196            let inmemory_selections = selections
 3197                .iter()
 3198                .map(|s| {
 3199                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3200                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3201                })
 3202                .collect();
 3203            self.update_restoration_data(cx, |data| {
 3204                data.selections = inmemory_selections;
 3205            });
 3206
 3207            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3208                && let Some(workspace_id) =
 3209                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3210            {
 3211                let snapshot = self.buffer().read(cx).snapshot(cx);
 3212                let selections = selections.clone();
 3213                let background_executor = cx.background_executor().clone();
 3214                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3215                self.serialize_selections = cx.background_spawn(async move {
 3216                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3217                    let db_selections = selections
 3218                        .iter()
 3219                        .map(|selection| {
 3220                            (
 3221                                selection.start.to_offset(&snapshot),
 3222                                selection.end.to_offset(&snapshot),
 3223                            )
 3224                        })
 3225                        .collect();
 3226
 3227                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3228                        .await
 3229                        .with_context(|| {
 3230                            format!(
 3231                                "persisting editor selections for editor {editor_id}, \
 3232                                workspace {workspace_id:?}"
 3233                            )
 3234                        })
 3235                        .log_err();
 3236                });
 3237            }
 3238        }
 3239
 3240        cx.notify();
 3241    }
 3242
 3243    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3244        use text::ToOffset as _;
 3245        use text::ToPoint as _;
 3246
 3247        if self.mode.is_minimap()
 3248            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3249        {
 3250            return;
 3251        }
 3252
 3253        if !self.buffer().read(cx).is_singleton() {
 3254            return;
 3255        }
 3256
 3257        let display_snapshot = self
 3258            .display_map
 3259            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3260        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3261            return;
 3262        };
 3263        let inmemory_folds = display_snapshot
 3264            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3265            .map(|fold| {
 3266                fold.range.start.text_anchor.to_point(&snapshot)
 3267                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3268            })
 3269            .collect();
 3270        self.update_restoration_data(cx, |data| {
 3271            data.folds = inmemory_folds;
 3272        });
 3273
 3274        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3275            return;
 3276        };
 3277        let background_executor = cx.background_executor().clone();
 3278        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3279        let db_folds = display_snapshot
 3280            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3281            .map(|fold| {
 3282                (
 3283                    fold.range.start.text_anchor.to_offset(&snapshot),
 3284                    fold.range.end.text_anchor.to_offset(&snapshot),
 3285                )
 3286            })
 3287            .collect();
 3288        self.serialize_folds = cx.background_spawn(async move {
 3289            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3290            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3291                .await
 3292                .with_context(|| {
 3293                    format!(
 3294                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3295                    )
 3296                })
 3297                .log_err();
 3298        });
 3299    }
 3300
 3301    pub fn sync_selections(
 3302        &mut self,
 3303        other: Entity<Editor>,
 3304        cx: &mut Context<Self>,
 3305    ) -> gpui::Subscription {
 3306        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3307        if !other_selections.is_empty() {
 3308            self.selections.change_with(cx, |selections| {
 3309                selections.select_anchors(other_selections);
 3310            });
 3311        }
 3312
 3313        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3314            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3315                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3316                if other_selections.is_empty() {
 3317                    return;
 3318                }
 3319                this.selections.change_with(cx, |selections| {
 3320                    selections.select_anchors(other_selections);
 3321                });
 3322            }
 3323        });
 3324
 3325        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3326            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3327                let these_selections = this.selections.disjoint_anchors().to_vec();
 3328                if these_selections.is_empty() {
 3329                    return;
 3330                }
 3331                other.update(cx, |other_editor, cx| {
 3332                    other_editor.selections.change_with(cx, |selections| {
 3333                        selections.select_anchors(these_selections);
 3334                    })
 3335                });
 3336            }
 3337        });
 3338
 3339        Subscription::join(other_subscription, this_subscription)
 3340    }
 3341
 3342    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3343    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3344    /// effects of selection change occur at the end of the transaction.
 3345    pub fn change_selections<R>(
 3346        &mut self,
 3347        effects: SelectionEffects,
 3348        window: &mut Window,
 3349        cx: &mut Context<Self>,
 3350        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3351    ) -> R {
 3352        if let Some(state) = &mut self.deferred_selection_effects_state {
 3353            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3354            state.effects.completions = effects.completions;
 3355            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3356            let (changed, result) = self.selections.change_with(cx, change);
 3357            state.changed |= changed;
 3358            return result;
 3359        }
 3360        let mut state = DeferredSelectionEffectsState {
 3361            changed: false,
 3362            effects,
 3363            old_cursor_position: self.selections.newest_anchor().head(),
 3364            history_entry: SelectionHistoryEntry {
 3365                selections: self.selections.disjoint_anchors_arc(),
 3366                select_next_state: self.select_next_state.clone(),
 3367                select_prev_state: self.select_prev_state.clone(),
 3368                add_selections_state: self.add_selections_state.clone(),
 3369            },
 3370        };
 3371        let (changed, result) = self.selections.change_with(cx, change);
 3372        state.changed = state.changed || changed;
 3373        if self.defer_selection_effects {
 3374            self.deferred_selection_effects_state = Some(state);
 3375        } else {
 3376            self.apply_selection_effects(state, window, cx);
 3377        }
 3378        result
 3379    }
 3380
 3381    /// Defers the effects of selection change, so that the effects of multiple calls to
 3382    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3383    /// to selection history and the state of popovers based on selection position aren't
 3384    /// erroneously updated.
 3385    pub fn with_selection_effects_deferred<R>(
 3386        &mut self,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3390    ) -> R {
 3391        let already_deferred = self.defer_selection_effects;
 3392        self.defer_selection_effects = true;
 3393        let result = update(self, window, cx);
 3394        if !already_deferred {
 3395            self.defer_selection_effects = false;
 3396            if let Some(state) = self.deferred_selection_effects_state.take() {
 3397                self.apply_selection_effects(state, window, cx);
 3398            }
 3399        }
 3400        result
 3401    }
 3402
 3403    fn apply_selection_effects(
 3404        &mut self,
 3405        state: DeferredSelectionEffectsState,
 3406        window: &mut Window,
 3407        cx: &mut Context<Self>,
 3408    ) {
 3409        if state.changed {
 3410            self.selection_history.push(state.history_entry);
 3411
 3412            if let Some(autoscroll) = state.effects.scroll {
 3413                self.request_autoscroll(autoscroll, cx);
 3414            }
 3415
 3416            let old_cursor_position = &state.old_cursor_position;
 3417
 3418            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3419
 3420            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3421                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3422            }
 3423        }
 3424    }
 3425
 3426    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3427    where
 3428        I: IntoIterator<Item = (Range<S>, T)>,
 3429        S: ToOffset,
 3430        T: Into<Arc<str>>,
 3431    {
 3432        if self.read_only(cx) {
 3433            return;
 3434        }
 3435
 3436        self.buffer
 3437            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3438    }
 3439
 3440    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3441    where
 3442        I: IntoIterator<Item = (Range<S>, T)>,
 3443        S: ToOffset,
 3444        T: Into<Arc<str>>,
 3445    {
 3446        if self.read_only(cx) {
 3447            return;
 3448        }
 3449
 3450        self.buffer.update(cx, |buffer, cx| {
 3451            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3452        });
 3453    }
 3454
 3455    pub fn edit_with_block_indent<I, S, T>(
 3456        &mut self,
 3457        edits: I,
 3458        original_indent_columns: Vec<Option<u32>>,
 3459        cx: &mut Context<Self>,
 3460    ) where
 3461        I: IntoIterator<Item = (Range<S>, T)>,
 3462        S: ToOffset,
 3463        T: Into<Arc<str>>,
 3464    {
 3465        if self.read_only(cx) {
 3466            return;
 3467        }
 3468
 3469        self.buffer.update(cx, |buffer, cx| {
 3470            buffer.edit(
 3471                edits,
 3472                Some(AutoindentMode::Block {
 3473                    original_indent_columns,
 3474                }),
 3475                cx,
 3476            )
 3477        });
 3478    }
 3479
 3480    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3481        self.hide_context_menu(window, cx);
 3482
 3483        match phase {
 3484            SelectPhase::Begin {
 3485                position,
 3486                add,
 3487                click_count,
 3488            } => self.begin_selection(position, add, click_count, window, cx),
 3489            SelectPhase::BeginColumnar {
 3490                position,
 3491                goal_column,
 3492                reset,
 3493                mode,
 3494            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3495            SelectPhase::Extend {
 3496                position,
 3497                click_count,
 3498            } => self.extend_selection(position, click_count, window, cx),
 3499            SelectPhase::Update {
 3500                position,
 3501                goal_column,
 3502                scroll_delta,
 3503            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3504            SelectPhase::End => self.end_selection(window, cx),
 3505        }
 3506    }
 3507
 3508    fn extend_selection(
 3509        &mut self,
 3510        position: DisplayPoint,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3516        let tail = self.selections.newest::<usize>(cx).tail();
 3517        let click_count = click_count.max(match self.selections.select_mode() {
 3518            SelectMode::Character => 1,
 3519            SelectMode::Word(_) => 2,
 3520            SelectMode::Line(_) => 3,
 3521            SelectMode::All => 4,
 3522        });
 3523        self.begin_selection(position, false, click_count, window, cx);
 3524
 3525        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3526
 3527        let current_selection = match self.selections.select_mode() {
 3528            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3529            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3530        };
 3531
 3532        let mut pending_selection = self
 3533            .selections
 3534            .pending_anchor()
 3535            .cloned()
 3536            .expect("extend_selection not called with pending selection");
 3537
 3538        if pending_selection
 3539            .start
 3540            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3541            == Ordering::Greater
 3542        {
 3543            pending_selection.start = current_selection.start;
 3544        }
 3545        if pending_selection
 3546            .end
 3547            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3548            == Ordering::Less
 3549        {
 3550            pending_selection.end = current_selection.end;
 3551            pending_selection.reversed = true;
 3552        }
 3553
 3554        let mut pending_mode = self.selections.pending_mode().unwrap();
 3555        match &mut pending_mode {
 3556            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3557            _ => {}
 3558        }
 3559
 3560        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3561            SelectionEffects::scroll(Autoscroll::fit())
 3562        } else {
 3563            SelectionEffects::no_scroll()
 3564        };
 3565
 3566        self.change_selections(effects, window, cx, |s| {
 3567            s.set_pending(pending_selection.clone(), pending_mode);
 3568            s.set_is_extending(true);
 3569        });
 3570    }
 3571
 3572    fn begin_selection(
 3573        &mut self,
 3574        position: DisplayPoint,
 3575        add: bool,
 3576        click_count: usize,
 3577        window: &mut Window,
 3578        cx: &mut Context<Self>,
 3579    ) {
 3580        if !self.focus_handle.is_focused(window) {
 3581            self.last_focused_descendant = None;
 3582            window.focus(&self.focus_handle);
 3583        }
 3584
 3585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3586        let buffer = display_map.buffer_snapshot();
 3587        let position = display_map.clip_point(position, Bias::Left);
 3588
 3589        let start;
 3590        let end;
 3591        let mode;
 3592        let mut auto_scroll;
 3593        match click_count {
 3594            1 => {
 3595                start = buffer.anchor_before(position.to_point(&display_map));
 3596                end = start;
 3597                mode = SelectMode::Character;
 3598                auto_scroll = true;
 3599            }
 3600            2 => {
 3601                let position = display_map
 3602                    .clip_point(position, Bias::Left)
 3603                    .to_offset(&display_map, Bias::Left);
 3604                let (range, _) = buffer.surrounding_word(position, None);
 3605                start = buffer.anchor_before(range.start);
 3606                end = buffer.anchor_before(range.end);
 3607                mode = SelectMode::Word(start..end);
 3608                auto_scroll = true;
 3609            }
 3610            3 => {
 3611                let position = display_map
 3612                    .clip_point(position, Bias::Left)
 3613                    .to_point(&display_map);
 3614                let line_start = display_map.prev_line_boundary(position).0;
 3615                let next_line_start = buffer.clip_point(
 3616                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3617                    Bias::Left,
 3618                );
 3619                start = buffer.anchor_before(line_start);
 3620                end = buffer.anchor_before(next_line_start);
 3621                mode = SelectMode::Line(start..end);
 3622                auto_scroll = true;
 3623            }
 3624            _ => {
 3625                start = buffer.anchor_before(0);
 3626                end = buffer.anchor_before(buffer.len());
 3627                mode = SelectMode::All;
 3628                auto_scroll = false;
 3629            }
 3630        }
 3631        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3632
 3633        let point_to_delete: Option<usize> = {
 3634            let selected_points: Vec<Selection<Point>> =
 3635                self.selections.disjoint_in_range(start..end, cx);
 3636
 3637            if !add || click_count > 1 {
 3638                None
 3639            } else if !selected_points.is_empty() {
 3640                Some(selected_points[0].id)
 3641            } else {
 3642                let clicked_point_already_selected =
 3643                    self.selections.disjoint_anchors().iter().find(|selection| {
 3644                        selection.start.to_point(buffer) == start.to_point(buffer)
 3645                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3646                    });
 3647
 3648                clicked_point_already_selected.map(|selection| selection.id)
 3649            }
 3650        };
 3651
 3652        let selections_count = self.selections.count();
 3653        let effects = if auto_scroll {
 3654            SelectionEffects::default()
 3655        } else {
 3656            SelectionEffects::no_scroll()
 3657        };
 3658
 3659        self.change_selections(effects, window, cx, |s| {
 3660            if let Some(point_to_delete) = point_to_delete {
 3661                s.delete(point_to_delete);
 3662
 3663                if selections_count == 1 {
 3664                    s.set_pending_anchor_range(start..end, mode);
 3665                }
 3666            } else {
 3667                if !add {
 3668                    s.clear_disjoint();
 3669                }
 3670
 3671                s.set_pending_anchor_range(start..end, mode);
 3672            }
 3673        });
 3674    }
 3675
 3676    fn begin_columnar_selection(
 3677        &mut self,
 3678        position: DisplayPoint,
 3679        goal_column: u32,
 3680        reset: bool,
 3681        mode: ColumnarMode,
 3682        window: &mut Window,
 3683        cx: &mut Context<Self>,
 3684    ) {
 3685        if !self.focus_handle.is_focused(window) {
 3686            self.last_focused_descendant = None;
 3687            window.focus(&self.focus_handle);
 3688        }
 3689
 3690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3691
 3692        if reset {
 3693            let pointer_position = display_map
 3694                .buffer_snapshot()
 3695                .anchor_before(position.to_point(&display_map));
 3696
 3697            self.change_selections(
 3698                SelectionEffects::scroll(Autoscroll::newest()),
 3699                window,
 3700                cx,
 3701                |s| {
 3702                    s.clear_disjoint();
 3703                    s.set_pending_anchor_range(
 3704                        pointer_position..pointer_position,
 3705                        SelectMode::Character,
 3706                    );
 3707                },
 3708            );
 3709        };
 3710
 3711        let tail = self.selections.newest::<Point>(cx).tail();
 3712        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3713        self.columnar_selection_state = match mode {
 3714            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3715                selection_tail: selection_anchor,
 3716                display_point: if reset {
 3717                    if position.column() != goal_column {
 3718                        Some(DisplayPoint::new(position.row(), goal_column))
 3719                    } else {
 3720                        None
 3721                    }
 3722                } else {
 3723                    None
 3724                },
 3725            }),
 3726            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3727                selection_tail: selection_anchor,
 3728            }),
 3729        };
 3730
 3731        if !reset {
 3732            self.select_columns(position, goal_column, &display_map, window, cx);
 3733        }
 3734    }
 3735
 3736    fn update_selection(
 3737        &mut self,
 3738        position: DisplayPoint,
 3739        goal_column: u32,
 3740        scroll_delta: gpui::Point<f32>,
 3741        window: &mut Window,
 3742        cx: &mut Context<Self>,
 3743    ) {
 3744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3745
 3746        if self.columnar_selection_state.is_some() {
 3747            self.select_columns(position, goal_column, &display_map, window, cx);
 3748        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3749            let buffer = display_map.buffer_snapshot();
 3750            let head;
 3751            let tail;
 3752            let mode = self.selections.pending_mode().unwrap();
 3753            match &mode {
 3754                SelectMode::Character => {
 3755                    head = position.to_point(&display_map);
 3756                    tail = pending.tail().to_point(buffer);
 3757                }
 3758                SelectMode::Word(original_range) => {
 3759                    let offset = display_map
 3760                        .clip_point(position, Bias::Left)
 3761                        .to_offset(&display_map, Bias::Left);
 3762                    let original_range = original_range.to_offset(buffer);
 3763
 3764                    let head_offset = if buffer.is_inside_word(offset, None)
 3765                        || original_range.contains(&offset)
 3766                    {
 3767                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3768                        if word_range.start < original_range.start {
 3769                            word_range.start
 3770                        } else {
 3771                            word_range.end
 3772                        }
 3773                    } else {
 3774                        offset
 3775                    };
 3776
 3777                    head = head_offset.to_point(buffer);
 3778                    if head_offset <= original_range.start {
 3779                        tail = original_range.end.to_point(buffer);
 3780                    } else {
 3781                        tail = original_range.start.to_point(buffer);
 3782                    }
 3783                }
 3784                SelectMode::Line(original_range) => {
 3785                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3786
 3787                    let position = display_map
 3788                        .clip_point(position, Bias::Left)
 3789                        .to_point(&display_map);
 3790                    let line_start = display_map.prev_line_boundary(position).0;
 3791                    let next_line_start = buffer.clip_point(
 3792                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3793                        Bias::Left,
 3794                    );
 3795
 3796                    if line_start < original_range.start {
 3797                        head = line_start
 3798                    } else {
 3799                        head = next_line_start
 3800                    }
 3801
 3802                    if head <= original_range.start {
 3803                        tail = original_range.end;
 3804                    } else {
 3805                        tail = original_range.start;
 3806                    }
 3807                }
 3808                SelectMode::All => {
 3809                    return;
 3810                }
 3811            };
 3812
 3813            if head < tail {
 3814                pending.start = buffer.anchor_before(head);
 3815                pending.end = buffer.anchor_before(tail);
 3816                pending.reversed = true;
 3817            } else {
 3818                pending.start = buffer.anchor_before(tail);
 3819                pending.end = buffer.anchor_before(head);
 3820                pending.reversed = false;
 3821            }
 3822
 3823            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3824                s.set_pending(pending.clone(), mode);
 3825            });
 3826        } else {
 3827            log::error!("update_selection dispatched with no pending selection");
 3828            return;
 3829        }
 3830
 3831        self.apply_scroll_delta(scroll_delta, window, cx);
 3832        cx.notify();
 3833    }
 3834
 3835    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3836        self.columnar_selection_state.take();
 3837        if let Some(pending_mode) = self.selections.pending_mode() {
 3838            let selections = self.selections.all::<usize>(cx);
 3839            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3840                s.select(selections);
 3841                s.clear_pending();
 3842                if s.is_extending() {
 3843                    s.set_is_extending(false);
 3844                } else {
 3845                    s.set_select_mode(pending_mode);
 3846                }
 3847            });
 3848        }
 3849    }
 3850
 3851    fn select_columns(
 3852        &mut self,
 3853        head: DisplayPoint,
 3854        goal_column: u32,
 3855        display_map: &DisplaySnapshot,
 3856        window: &mut Window,
 3857        cx: &mut Context<Self>,
 3858    ) {
 3859        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3860            return;
 3861        };
 3862
 3863        let tail = match columnar_state {
 3864            ColumnarSelectionState::FromMouse {
 3865                selection_tail,
 3866                display_point,
 3867            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3868            ColumnarSelectionState::FromSelection { selection_tail } => {
 3869                selection_tail.to_display_point(display_map)
 3870            }
 3871        };
 3872
 3873        let start_row = cmp::min(tail.row(), head.row());
 3874        let end_row = cmp::max(tail.row(), head.row());
 3875        let start_column = cmp::min(tail.column(), goal_column);
 3876        let end_column = cmp::max(tail.column(), goal_column);
 3877        let reversed = start_column < tail.column();
 3878
 3879        let selection_ranges = (start_row.0..=end_row.0)
 3880            .map(DisplayRow)
 3881            .filter_map(|row| {
 3882                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3883                    || start_column <= display_map.line_len(row))
 3884                    && !display_map.is_block_line(row)
 3885                {
 3886                    let start = display_map
 3887                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3888                        .to_point(display_map);
 3889                    let end = display_map
 3890                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3891                        .to_point(display_map);
 3892                    if reversed {
 3893                        Some(end..start)
 3894                    } else {
 3895                        Some(start..end)
 3896                    }
 3897                } else {
 3898                    None
 3899                }
 3900            })
 3901            .collect::<Vec<_>>();
 3902
 3903        let ranges = match columnar_state {
 3904            ColumnarSelectionState::FromMouse { .. } => {
 3905                let mut non_empty_ranges = selection_ranges
 3906                    .iter()
 3907                    .filter(|selection_range| selection_range.start != selection_range.end)
 3908                    .peekable();
 3909                if non_empty_ranges.peek().is_some() {
 3910                    non_empty_ranges.cloned().collect()
 3911                } else {
 3912                    selection_ranges
 3913                }
 3914            }
 3915            _ => selection_ranges,
 3916        };
 3917
 3918        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3919            s.select_ranges(ranges);
 3920        });
 3921        cx.notify();
 3922    }
 3923
 3924    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3925        self.selections
 3926            .all_adjusted(cx)
 3927            .iter()
 3928            .any(|selection| !selection.is_empty())
 3929    }
 3930
 3931    pub fn has_pending_nonempty_selection(&self) -> bool {
 3932        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3933            Some(Selection { start, end, .. }) => start != end,
 3934            None => false,
 3935        };
 3936
 3937        pending_nonempty_selection
 3938            || (self.columnar_selection_state.is_some()
 3939                && self.selections.disjoint_anchors().len() > 1)
 3940    }
 3941
 3942    pub fn has_pending_selection(&self) -> bool {
 3943        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3944    }
 3945
 3946    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3947        self.selection_mark_mode = false;
 3948        self.selection_drag_state = SelectionDragState::None;
 3949
 3950        if self.clear_expanded_diff_hunks(cx) {
 3951            cx.notify();
 3952            return;
 3953        }
 3954        if self.dismiss_menus_and_popups(true, window, cx) {
 3955            return;
 3956        }
 3957
 3958        if self.mode.is_full()
 3959            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3960        {
 3961            return;
 3962        }
 3963
 3964        cx.propagate();
 3965    }
 3966
 3967    pub fn dismiss_menus_and_popups(
 3968        &mut self,
 3969        is_user_requested: bool,
 3970        window: &mut Window,
 3971        cx: &mut Context<Self>,
 3972    ) -> bool {
 3973        if self.take_rename(false, window, cx).is_some() {
 3974            return true;
 3975        }
 3976
 3977        if hide_hover(self, cx) {
 3978            return true;
 3979        }
 3980
 3981        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3982            return true;
 3983        }
 3984
 3985        if self.hide_context_menu(window, cx).is_some() {
 3986            return true;
 3987        }
 3988
 3989        if self.mouse_context_menu.take().is_some() {
 3990            return true;
 3991        }
 3992
 3993        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3994            return true;
 3995        }
 3996
 3997        if self.snippet_stack.pop().is_some() {
 3998            return true;
 3999        }
 4000
 4001        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4002            self.dismiss_diagnostics(cx);
 4003            return true;
 4004        }
 4005
 4006        false
 4007    }
 4008
 4009    fn linked_editing_ranges_for(
 4010        &self,
 4011        selection: Range<text::Anchor>,
 4012        cx: &App,
 4013    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4014        if self.linked_edit_ranges.is_empty() {
 4015            return None;
 4016        }
 4017        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4018            selection.end.buffer_id.and_then(|end_buffer_id| {
 4019                if selection.start.buffer_id != Some(end_buffer_id) {
 4020                    return None;
 4021                }
 4022                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4023                let snapshot = buffer.read(cx).snapshot();
 4024                self.linked_edit_ranges
 4025                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4026                    .map(|ranges| (ranges, snapshot, buffer))
 4027            })?;
 4028        use text::ToOffset as TO;
 4029        // find offset from the start of current range to current cursor position
 4030        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4031
 4032        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4033        let start_difference = start_offset - start_byte_offset;
 4034        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4035        let end_difference = end_offset - start_byte_offset;
 4036        // Current range has associated linked ranges.
 4037        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4038        for range in linked_ranges.iter() {
 4039            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4040            let end_offset = start_offset + end_difference;
 4041            let start_offset = start_offset + start_difference;
 4042            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4043                continue;
 4044            }
 4045            if self.selections.disjoint_anchor_ranges().any(|s| {
 4046                if s.start.buffer_id != selection.start.buffer_id
 4047                    || s.end.buffer_id != selection.end.buffer_id
 4048                {
 4049                    return false;
 4050                }
 4051                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4052                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4053            }) {
 4054                continue;
 4055            }
 4056            let start = buffer_snapshot.anchor_after(start_offset);
 4057            let end = buffer_snapshot.anchor_after(end_offset);
 4058            linked_edits
 4059                .entry(buffer.clone())
 4060                .or_default()
 4061                .push(start..end);
 4062        }
 4063        Some(linked_edits)
 4064    }
 4065
 4066    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4067        let text: Arc<str> = text.into();
 4068
 4069        if self.read_only(cx) {
 4070            return;
 4071        }
 4072
 4073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4074
 4075        let selections = self.selections.all_adjusted(cx);
 4076        let mut bracket_inserted = false;
 4077        let mut edits = Vec::new();
 4078        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4079        let mut new_selections = Vec::with_capacity(selections.len());
 4080        let mut new_autoclose_regions = Vec::new();
 4081        let snapshot = self.buffer.read(cx).read(cx);
 4082        let mut clear_linked_edit_ranges = false;
 4083
 4084        for (selection, autoclose_region) in
 4085            self.selections_with_autoclose_regions(selections, &snapshot)
 4086        {
 4087            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4088                // Determine if the inserted text matches the opening or closing
 4089                // bracket of any of this language's bracket pairs.
 4090                let mut bracket_pair = None;
 4091                let mut is_bracket_pair_start = false;
 4092                let mut is_bracket_pair_end = false;
 4093                if !text.is_empty() {
 4094                    let mut bracket_pair_matching_end = None;
 4095                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4096                    //  and they are removing the character that triggered IME popup.
 4097                    for (pair, enabled) in scope.brackets() {
 4098                        if !pair.close && !pair.surround {
 4099                            continue;
 4100                        }
 4101
 4102                        if enabled && pair.start.ends_with(text.as_ref()) {
 4103                            let prefix_len = pair.start.len() - text.len();
 4104                            let preceding_text_matches_prefix = prefix_len == 0
 4105                                || (selection.start.column >= (prefix_len as u32)
 4106                                    && snapshot.contains_str_at(
 4107                                        Point::new(
 4108                                            selection.start.row,
 4109                                            selection.start.column - (prefix_len as u32),
 4110                                        ),
 4111                                        &pair.start[..prefix_len],
 4112                                    ));
 4113                            if preceding_text_matches_prefix {
 4114                                bracket_pair = Some(pair.clone());
 4115                                is_bracket_pair_start = true;
 4116                                break;
 4117                            }
 4118                        }
 4119                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4120                        {
 4121                            // take first bracket pair matching end, but don't break in case a later bracket
 4122                            // pair matches start
 4123                            bracket_pair_matching_end = Some(pair.clone());
 4124                        }
 4125                    }
 4126                    if let Some(end) = bracket_pair_matching_end
 4127                        && bracket_pair.is_none()
 4128                    {
 4129                        bracket_pair = Some(end);
 4130                        is_bracket_pair_end = true;
 4131                    }
 4132                }
 4133
 4134                if let Some(bracket_pair) = bracket_pair {
 4135                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4136                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4137                    let auto_surround =
 4138                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4139                    if selection.is_empty() {
 4140                        if is_bracket_pair_start {
 4141                            // If the inserted text is a suffix of an opening bracket and the
 4142                            // selection is preceded by the rest of the opening bracket, then
 4143                            // insert the closing bracket.
 4144                            let following_text_allows_autoclose = snapshot
 4145                                .chars_at(selection.start)
 4146                                .next()
 4147                                .is_none_or(|c| scope.should_autoclose_before(c));
 4148
 4149                            let preceding_text_allows_autoclose = selection.start.column == 0
 4150                                || snapshot
 4151                                    .reversed_chars_at(selection.start)
 4152                                    .next()
 4153                                    .is_none_or(|c| {
 4154                                        bracket_pair.start != bracket_pair.end
 4155                                            || !snapshot
 4156                                                .char_classifier_at(selection.start)
 4157                                                .is_word(c)
 4158                                    });
 4159
 4160                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4161                                && bracket_pair.start.len() == 1
 4162                            {
 4163                                let target = bracket_pair.start.chars().next().unwrap();
 4164                                let current_line_count = snapshot
 4165                                    .reversed_chars_at(selection.start)
 4166                                    .take_while(|&c| c != '\n')
 4167                                    .filter(|&c| c == target)
 4168                                    .count();
 4169                                current_line_count % 2 == 1
 4170                            } else {
 4171                                false
 4172                            };
 4173
 4174                            if autoclose
 4175                                && bracket_pair.close
 4176                                && following_text_allows_autoclose
 4177                                && preceding_text_allows_autoclose
 4178                                && !is_closing_quote
 4179                            {
 4180                                let anchor = snapshot.anchor_before(selection.end);
 4181                                new_selections.push((selection.map(|_| anchor), text.len()));
 4182                                new_autoclose_regions.push((
 4183                                    anchor,
 4184                                    text.len(),
 4185                                    selection.id,
 4186                                    bracket_pair.clone(),
 4187                                ));
 4188                                edits.push((
 4189                                    selection.range(),
 4190                                    format!("{}{}", text, bracket_pair.end).into(),
 4191                                ));
 4192                                bracket_inserted = true;
 4193                                continue;
 4194                            }
 4195                        }
 4196
 4197                        if let Some(region) = autoclose_region {
 4198                            // If the selection is followed by an auto-inserted closing bracket,
 4199                            // then don't insert that closing bracket again; just move the selection
 4200                            // past the closing bracket.
 4201                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4202                                && text.as_ref() == region.pair.end.as_str()
 4203                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4204                            if should_skip {
 4205                                let anchor = snapshot.anchor_after(selection.end);
 4206                                new_selections
 4207                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4208                                continue;
 4209                            }
 4210                        }
 4211
 4212                        let always_treat_brackets_as_autoclosed = snapshot
 4213                            .language_settings_at(selection.start, cx)
 4214                            .always_treat_brackets_as_autoclosed;
 4215                        if always_treat_brackets_as_autoclosed
 4216                            && is_bracket_pair_end
 4217                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4218                        {
 4219                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4220                            // and the inserted text is a closing bracket and the selection is followed
 4221                            // by the closing bracket then move the selection past the closing bracket.
 4222                            let anchor = snapshot.anchor_after(selection.end);
 4223                            new_selections.push((selection.map(|_| anchor), text.len()));
 4224                            continue;
 4225                        }
 4226                    }
 4227                    // If an opening bracket is 1 character long and is typed while
 4228                    // text is selected, then surround that text with the bracket pair.
 4229                    else if auto_surround
 4230                        && bracket_pair.surround
 4231                        && is_bracket_pair_start
 4232                        && bracket_pair.start.chars().count() == 1
 4233                    {
 4234                        edits.push((selection.start..selection.start, text.clone()));
 4235                        edits.push((
 4236                            selection.end..selection.end,
 4237                            bracket_pair.end.as_str().into(),
 4238                        ));
 4239                        bracket_inserted = true;
 4240                        new_selections.push((
 4241                            Selection {
 4242                                id: selection.id,
 4243                                start: snapshot.anchor_after(selection.start),
 4244                                end: snapshot.anchor_before(selection.end),
 4245                                reversed: selection.reversed,
 4246                                goal: selection.goal,
 4247                            },
 4248                            0,
 4249                        ));
 4250                        continue;
 4251                    }
 4252                }
 4253            }
 4254
 4255            if self.auto_replace_emoji_shortcode
 4256                && selection.is_empty()
 4257                && text.as_ref().ends_with(':')
 4258                && let Some(possible_emoji_short_code) =
 4259                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4260                && !possible_emoji_short_code.is_empty()
 4261                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4262            {
 4263                let emoji_shortcode_start = Point::new(
 4264                    selection.start.row,
 4265                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4266                );
 4267
 4268                // Remove shortcode from buffer
 4269                edits.push((
 4270                    emoji_shortcode_start..selection.start,
 4271                    "".to_string().into(),
 4272                ));
 4273                new_selections.push((
 4274                    Selection {
 4275                        id: selection.id,
 4276                        start: snapshot.anchor_after(emoji_shortcode_start),
 4277                        end: snapshot.anchor_before(selection.start),
 4278                        reversed: selection.reversed,
 4279                        goal: selection.goal,
 4280                    },
 4281                    0,
 4282                ));
 4283
 4284                // Insert emoji
 4285                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4286                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4287                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4288
 4289                continue;
 4290            }
 4291
 4292            // If not handling any auto-close operation, then just replace the selected
 4293            // text with the given input and move the selection to the end of the
 4294            // newly inserted text.
 4295            let anchor = snapshot.anchor_after(selection.end);
 4296            if !self.linked_edit_ranges.is_empty() {
 4297                let start_anchor = snapshot.anchor_before(selection.start);
 4298
 4299                let is_word_char = text.chars().next().is_none_or(|char| {
 4300                    let classifier = snapshot
 4301                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4302                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4303                    classifier.is_word(char)
 4304                });
 4305
 4306                if is_word_char {
 4307                    if let Some(ranges) = self
 4308                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4309                    {
 4310                        for (buffer, edits) in ranges {
 4311                            linked_edits
 4312                                .entry(buffer.clone())
 4313                                .or_default()
 4314                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4315                        }
 4316                    }
 4317                } else {
 4318                    clear_linked_edit_ranges = true;
 4319                }
 4320            }
 4321
 4322            new_selections.push((selection.map(|_| anchor), 0));
 4323            edits.push((selection.start..selection.end, text.clone()));
 4324        }
 4325
 4326        drop(snapshot);
 4327
 4328        self.transact(window, cx, |this, window, cx| {
 4329            if clear_linked_edit_ranges {
 4330                this.linked_edit_ranges.clear();
 4331            }
 4332            let initial_buffer_versions =
 4333                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4334
 4335            this.buffer.update(cx, |buffer, cx| {
 4336                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4337            });
 4338            for (buffer, edits) in linked_edits {
 4339                buffer.update(cx, |buffer, cx| {
 4340                    let snapshot = buffer.snapshot();
 4341                    let edits = edits
 4342                        .into_iter()
 4343                        .map(|(range, text)| {
 4344                            use text::ToPoint as TP;
 4345                            let end_point = TP::to_point(&range.end, &snapshot);
 4346                            let start_point = TP::to_point(&range.start, &snapshot);
 4347                            (start_point..end_point, text)
 4348                        })
 4349                        .sorted_by_key(|(range, _)| range.start);
 4350                    buffer.edit(edits, None, cx);
 4351                })
 4352            }
 4353            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4354            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4355            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4356            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4357                .zip(new_selection_deltas)
 4358                .map(|(selection, delta)| Selection {
 4359                    id: selection.id,
 4360                    start: selection.start + delta,
 4361                    end: selection.end + delta,
 4362                    reversed: selection.reversed,
 4363                    goal: SelectionGoal::None,
 4364                })
 4365                .collect::<Vec<_>>();
 4366
 4367            let mut i = 0;
 4368            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4369                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4370                let start = map.buffer_snapshot().anchor_before(position);
 4371                let end = map.buffer_snapshot().anchor_after(position);
 4372                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4373                    match existing_state
 4374                        .range
 4375                        .start
 4376                        .cmp(&start, map.buffer_snapshot())
 4377                    {
 4378                        Ordering::Less => i += 1,
 4379                        Ordering::Greater => break,
 4380                        Ordering::Equal => {
 4381                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4382                                Ordering::Less => i += 1,
 4383                                Ordering::Equal => break,
 4384                                Ordering::Greater => break,
 4385                            }
 4386                        }
 4387                    }
 4388                }
 4389                this.autoclose_regions.insert(
 4390                    i,
 4391                    AutocloseRegion {
 4392                        selection_id,
 4393                        range: start..end,
 4394                        pair,
 4395                    },
 4396                );
 4397            }
 4398
 4399            let had_active_edit_prediction = this.has_active_edit_prediction();
 4400            this.change_selections(
 4401                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4402                window,
 4403                cx,
 4404                |s| s.select(new_selections),
 4405            );
 4406
 4407            if !bracket_inserted
 4408                && let Some(on_type_format_task) =
 4409                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4410            {
 4411                on_type_format_task.detach_and_log_err(cx);
 4412            }
 4413
 4414            let editor_settings = EditorSettings::get_global(cx);
 4415            if bracket_inserted
 4416                && (editor_settings.auto_signature_help
 4417                    || editor_settings.show_signature_help_after_edits)
 4418            {
 4419                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4420            }
 4421
 4422            let trigger_in_words =
 4423                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4424            if this.hard_wrap.is_some() {
 4425                let latest: Range<Point> = this.selections.newest(cx).range();
 4426                if latest.is_empty()
 4427                    && this
 4428                        .buffer()
 4429                        .read(cx)
 4430                        .snapshot(cx)
 4431                        .line_len(MultiBufferRow(latest.start.row))
 4432                        == latest.start.column
 4433                {
 4434                    this.rewrap_impl(
 4435                        RewrapOptions {
 4436                            override_language_settings: true,
 4437                            preserve_existing_whitespace: true,
 4438                        },
 4439                        cx,
 4440                    )
 4441                }
 4442            }
 4443            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4444            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4445            this.refresh_edit_prediction(true, false, window, cx);
 4446            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4447        });
 4448    }
 4449
 4450    fn find_possible_emoji_shortcode_at_position(
 4451        snapshot: &MultiBufferSnapshot,
 4452        position: Point,
 4453    ) -> Option<String> {
 4454        let mut chars = Vec::new();
 4455        let mut found_colon = false;
 4456        for char in snapshot.reversed_chars_at(position).take(100) {
 4457            // Found a possible emoji shortcode in the middle of the buffer
 4458            if found_colon {
 4459                if char.is_whitespace() {
 4460                    chars.reverse();
 4461                    return Some(chars.iter().collect());
 4462                }
 4463                // If the previous character is not a whitespace, we are in the middle of a word
 4464                // and we only want to complete the shortcode if the word is made up of other emojis
 4465                let mut containing_word = String::new();
 4466                for ch in snapshot
 4467                    .reversed_chars_at(position)
 4468                    .skip(chars.len() + 1)
 4469                    .take(100)
 4470                {
 4471                    if ch.is_whitespace() {
 4472                        break;
 4473                    }
 4474                    containing_word.push(ch);
 4475                }
 4476                let containing_word = containing_word.chars().rev().collect::<String>();
 4477                if util::word_consists_of_emojis(containing_word.as_str()) {
 4478                    chars.reverse();
 4479                    return Some(chars.iter().collect());
 4480                }
 4481            }
 4482
 4483            if char.is_whitespace() || !char.is_ascii() {
 4484                return None;
 4485            }
 4486            if char == ':' {
 4487                found_colon = true;
 4488            } else {
 4489                chars.push(char);
 4490            }
 4491        }
 4492        // Found a possible emoji shortcode at the beginning of the buffer
 4493        chars.reverse();
 4494        Some(chars.iter().collect())
 4495    }
 4496
 4497    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4498        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4499        self.transact(window, cx, |this, window, cx| {
 4500            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4501                let selections = this.selections.all::<usize>(cx);
 4502                let multi_buffer = this.buffer.read(cx);
 4503                let buffer = multi_buffer.snapshot(cx);
 4504                selections
 4505                    .iter()
 4506                    .map(|selection| {
 4507                        let start_point = selection.start.to_point(&buffer);
 4508                        let mut existing_indent =
 4509                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4510                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4511                        let start = selection.start;
 4512                        let end = selection.end;
 4513                        let selection_is_empty = start == end;
 4514                        let language_scope = buffer.language_scope_at(start);
 4515                        let (
 4516                            comment_delimiter,
 4517                            doc_delimiter,
 4518                            insert_extra_newline,
 4519                            indent_on_newline,
 4520                            indent_on_extra_newline,
 4521                        ) = if let Some(language) = &language_scope {
 4522                            let mut insert_extra_newline =
 4523                                insert_extra_newline_brackets(&buffer, start..end, language)
 4524                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4525
 4526                            // Comment extension on newline is allowed only for cursor selections
 4527                            let comment_delimiter = maybe!({
 4528                                if !selection_is_empty {
 4529                                    return None;
 4530                                }
 4531
 4532                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4533                                    return None;
 4534                                }
 4535
 4536                                let delimiters = language.line_comment_prefixes();
 4537                                let max_len_of_delimiter =
 4538                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4539                                let (snapshot, range) =
 4540                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4541
 4542                                let num_of_whitespaces = snapshot
 4543                                    .chars_for_range(range.clone())
 4544                                    .take_while(|c| c.is_whitespace())
 4545                                    .count();
 4546                                let comment_candidate = snapshot
 4547                                    .chars_for_range(range.clone())
 4548                                    .skip(num_of_whitespaces)
 4549                                    .take(max_len_of_delimiter)
 4550                                    .collect::<String>();
 4551                                let (delimiter, trimmed_len) = delimiters
 4552                                    .iter()
 4553                                    .filter_map(|delimiter| {
 4554                                        let prefix = delimiter.trim_end();
 4555                                        if comment_candidate.starts_with(prefix) {
 4556                                            Some((delimiter, prefix.len()))
 4557                                        } else {
 4558                                            None
 4559                                        }
 4560                                    })
 4561                                    .max_by_key(|(_, len)| *len)?;
 4562
 4563                                if let Some(BlockCommentConfig {
 4564                                    start: block_start, ..
 4565                                }) = language.block_comment()
 4566                                {
 4567                                    let block_start_trimmed = block_start.trim_end();
 4568                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4569                                        let line_content = snapshot
 4570                                            .chars_for_range(range)
 4571                                            .skip(num_of_whitespaces)
 4572                                            .take(block_start_trimmed.len())
 4573                                            .collect::<String>();
 4574
 4575                                        if line_content.starts_with(block_start_trimmed) {
 4576                                            return None;
 4577                                        }
 4578                                    }
 4579                                }
 4580
 4581                                let cursor_is_placed_after_comment_marker =
 4582                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4583                                if cursor_is_placed_after_comment_marker {
 4584                                    Some(delimiter.clone())
 4585                                } else {
 4586                                    None
 4587                                }
 4588                            });
 4589
 4590                            let mut indent_on_newline = IndentSize::spaces(0);
 4591                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4592
 4593                            let doc_delimiter = maybe!({
 4594                                if !selection_is_empty {
 4595                                    return None;
 4596                                }
 4597
 4598                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4599                                    return None;
 4600                                }
 4601
 4602                                let BlockCommentConfig {
 4603                                    start: start_tag,
 4604                                    end: end_tag,
 4605                                    prefix: delimiter,
 4606                                    tab_size: len,
 4607                                } = language.documentation_comment()?;
 4608                                let is_within_block_comment = buffer
 4609                                    .language_scope_at(start_point)
 4610                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4611                                if !is_within_block_comment {
 4612                                    return None;
 4613                                }
 4614
 4615                                let (snapshot, range) =
 4616                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4617
 4618                                let num_of_whitespaces = snapshot
 4619                                    .chars_for_range(range.clone())
 4620                                    .take_while(|c| c.is_whitespace())
 4621                                    .count();
 4622
 4623                                // 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.
 4624                                let column = start_point.column;
 4625                                let cursor_is_after_start_tag = {
 4626                                    let start_tag_len = start_tag.len();
 4627                                    let start_tag_line = snapshot
 4628                                        .chars_for_range(range.clone())
 4629                                        .skip(num_of_whitespaces)
 4630                                        .take(start_tag_len)
 4631                                        .collect::<String>();
 4632                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4633                                        num_of_whitespaces + start_tag_len <= column as usize
 4634                                    } else {
 4635                                        false
 4636                                    }
 4637                                };
 4638
 4639                                let cursor_is_after_delimiter = {
 4640                                    let delimiter_trim = delimiter.trim_end();
 4641                                    let delimiter_line = snapshot
 4642                                        .chars_for_range(range.clone())
 4643                                        .skip(num_of_whitespaces)
 4644                                        .take(delimiter_trim.len())
 4645                                        .collect::<String>();
 4646                                    if delimiter_line.starts_with(delimiter_trim) {
 4647                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4648                                    } else {
 4649                                        false
 4650                                    }
 4651                                };
 4652
 4653                                let cursor_is_before_end_tag_if_exists = {
 4654                                    let mut char_position = 0u32;
 4655                                    let mut end_tag_offset = None;
 4656
 4657                                    'outer: for chunk in snapshot.text_for_range(range) {
 4658                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4659                                            let chars_before_match =
 4660                                                chunk[..byte_pos].chars().count() as u32;
 4661                                            end_tag_offset =
 4662                                                Some(char_position + chars_before_match);
 4663                                            break 'outer;
 4664                                        }
 4665                                        char_position += chunk.chars().count() as u32;
 4666                                    }
 4667
 4668                                    if let Some(end_tag_offset) = end_tag_offset {
 4669                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4670                                        if cursor_is_after_start_tag {
 4671                                            if cursor_is_before_end_tag {
 4672                                                insert_extra_newline = true;
 4673                                            }
 4674                                            let cursor_is_at_start_of_end_tag =
 4675                                                column == end_tag_offset;
 4676                                            if cursor_is_at_start_of_end_tag {
 4677                                                indent_on_extra_newline.len = *len;
 4678                                            }
 4679                                        }
 4680                                        cursor_is_before_end_tag
 4681                                    } else {
 4682                                        true
 4683                                    }
 4684                                };
 4685
 4686                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4687                                    && cursor_is_before_end_tag_if_exists
 4688                                {
 4689                                    if cursor_is_after_start_tag {
 4690                                        indent_on_newline.len = *len;
 4691                                    }
 4692                                    Some(delimiter.clone())
 4693                                } else {
 4694                                    None
 4695                                }
 4696                            });
 4697
 4698                            (
 4699                                comment_delimiter,
 4700                                doc_delimiter,
 4701                                insert_extra_newline,
 4702                                indent_on_newline,
 4703                                indent_on_extra_newline,
 4704                            )
 4705                        } else {
 4706                            (
 4707                                None,
 4708                                None,
 4709                                false,
 4710                                IndentSize::default(),
 4711                                IndentSize::default(),
 4712                            )
 4713                        };
 4714
 4715                        let prevent_auto_indent = doc_delimiter.is_some();
 4716                        let delimiter = comment_delimiter.or(doc_delimiter);
 4717
 4718                        let capacity_for_delimiter =
 4719                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4720                        let mut new_text = String::with_capacity(
 4721                            1 + capacity_for_delimiter
 4722                                + existing_indent.len as usize
 4723                                + indent_on_newline.len as usize
 4724                                + indent_on_extra_newline.len as usize,
 4725                        );
 4726                        new_text.push('\n');
 4727                        new_text.extend(existing_indent.chars());
 4728                        new_text.extend(indent_on_newline.chars());
 4729
 4730                        if let Some(delimiter) = &delimiter {
 4731                            new_text.push_str(delimiter);
 4732                        }
 4733
 4734                        if insert_extra_newline {
 4735                            new_text.push('\n');
 4736                            new_text.extend(existing_indent.chars());
 4737                            new_text.extend(indent_on_extra_newline.chars());
 4738                        }
 4739
 4740                        let anchor = buffer.anchor_after(end);
 4741                        let new_selection = selection.map(|_| anchor);
 4742                        (
 4743                            ((start..end, new_text), prevent_auto_indent),
 4744                            (insert_extra_newline, new_selection),
 4745                        )
 4746                    })
 4747                    .unzip()
 4748            };
 4749
 4750            let mut auto_indent_edits = Vec::new();
 4751            let mut edits = Vec::new();
 4752            for (edit, prevent_auto_indent) in edits_with_flags {
 4753                if prevent_auto_indent {
 4754                    edits.push(edit);
 4755                } else {
 4756                    auto_indent_edits.push(edit);
 4757                }
 4758            }
 4759            if !edits.is_empty() {
 4760                this.edit(edits, cx);
 4761            }
 4762            if !auto_indent_edits.is_empty() {
 4763                this.edit_with_autoindent(auto_indent_edits, cx);
 4764            }
 4765
 4766            let buffer = this.buffer.read(cx).snapshot(cx);
 4767            let new_selections = selection_info
 4768                .into_iter()
 4769                .map(|(extra_newline_inserted, new_selection)| {
 4770                    let mut cursor = new_selection.end.to_point(&buffer);
 4771                    if extra_newline_inserted {
 4772                        cursor.row -= 1;
 4773                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4774                    }
 4775                    new_selection.map(|_| cursor)
 4776                })
 4777                .collect();
 4778
 4779            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4780            this.refresh_edit_prediction(true, false, window, cx);
 4781        });
 4782    }
 4783
 4784    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4786
 4787        let buffer = self.buffer.read(cx);
 4788        let snapshot = buffer.snapshot(cx);
 4789
 4790        let mut edits = Vec::new();
 4791        let mut rows = Vec::new();
 4792
 4793        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4794            let cursor = selection.head();
 4795            let row = cursor.row;
 4796
 4797            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4798
 4799            let newline = "\n".to_string();
 4800            edits.push((start_of_line..start_of_line, newline));
 4801
 4802            rows.push(row + rows_inserted as u32);
 4803        }
 4804
 4805        self.transact(window, cx, |editor, window, cx| {
 4806            editor.edit(edits, cx);
 4807
 4808            editor.change_selections(Default::default(), window, cx, |s| {
 4809                let mut index = 0;
 4810                s.move_cursors_with(|map, _, _| {
 4811                    let row = rows[index];
 4812                    index += 1;
 4813
 4814                    let point = Point::new(row, 0);
 4815                    let boundary = map.next_line_boundary(point).1;
 4816                    let clipped = map.clip_point(boundary, Bias::Left);
 4817
 4818                    (clipped, SelectionGoal::None)
 4819                });
 4820            });
 4821
 4822            let mut indent_edits = Vec::new();
 4823            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4824            for row in rows {
 4825                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4826                for (row, indent) in indents {
 4827                    if indent.len == 0 {
 4828                        continue;
 4829                    }
 4830
 4831                    let text = match indent.kind {
 4832                        IndentKind::Space => " ".repeat(indent.len as usize),
 4833                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4834                    };
 4835                    let point = Point::new(row.0, 0);
 4836                    indent_edits.push((point..point, text));
 4837                }
 4838            }
 4839            editor.edit(indent_edits, cx);
 4840        });
 4841    }
 4842
 4843    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4845
 4846        let buffer = self.buffer.read(cx);
 4847        let snapshot = buffer.snapshot(cx);
 4848
 4849        let mut edits = Vec::new();
 4850        let mut rows = Vec::new();
 4851        let mut rows_inserted = 0;
 4852
 4853        for selection in self.selections.all_adjusted(cx) {
 4854            let cursor = selection.head();
 4855            let row = cursor.row;
 4856
 4857            let point = Point::new(row + 1, 0);
 4858            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4859
 4860            let newline = "\n".to_string();
 4861            edits.push((start_of_line..start_of_line, newline));
 4862
 4863            rows_inserted += 1;
 4864            rows.push(row + rows_inserted);
 4865        }
 4866
 4867        self.transact(window, cx, |editor, window, cx| {
 4868            editor.edit(edits, cx);
 4869
 4870            editor.change_selections(Default::default(), window, cx, |s| {
 4871                let mut index = 0;
 4872                s.move_cursors_with(|map, _, _| {
 4873                    let row = rows[index];
 4874                    index += 1;
 4875
 4876                    let point = Point::new(row, 0);
 4877                    let boundary = map.next_line_boundary(point).1;
 4878                    let clipped = map.clip_point(boundary, Bias::Left);
 4879
 4880                    (clipped, SelectionGoal::None)
 4881                });
 4882            });
 4883
 4884            let mut indent_edits = Vec::new();
 4885            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4886            for row in rows {
 4887                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4888                for (row, indent) in indents {
 4889                    if indent.len == 0 {
 4890                        continue;
 4891                    }
 4892
 4893                    let text = match indent.kind {
 4894                        IndentKind::Space => " ".repeat(indent.len as usize),
 4895                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4896                    };
 4897                    let point = Point::new(row.0, 0);
 4898                    indent_edits.push((point..point, text));
 4899                }
 4900            }
 4901            editor.edit(indent_edits, cx);
 4902        });
 4903    }
 4904
 4905    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4906        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4907            original_indent_columns: Vec::new(),
 4908        });
 4909        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4910    }
 4911
 4912    fn insert_with_autoindent_mode(
 4913        &mut self,
 4914        text: &str,
 4915        autoindent_mode: Option<AutoindentMode>,
 4916        window: &mut Window,
 4917        cx: &mut Context<Self>,
 4918    ) {
 4919        if self.read_only(cx) {
 4920            return;
 4921        }
 4922
 4923        let text: Arc<str> = text.into();
 4924        self.transact(window, cx, |this, window, cx| {
 4925            let old_selections = this.selections.all_adjusted(cx);
 4926            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4927                let anchors = {
 4928                    let snapshot = buffer.read(cx);
 4929                    old_selections
 4930                        .iter()
 4931                        .map(|s| {
 4932                            let anchor = snapshot.anchor_after(s.head());
 4933                            s.map(|_| anchor)
 4934                        })
 4935                        .collect::<Vec<_>>()
 4936                };
 4937                buffer.edit(
 4938                    old_selections
 4939                        .iter()
 4940                        .map(|s| (s.start..s.end, text.clone())),
 4941                    autoindent_mode,
 4942                    cx,
 4943                );
 4944                anchors
 4945            });
 4946
 4947            this.change_selections(Default::default(), window, cx, |s| {
 4948                s.select_anchors(selection_anchors);
 4949            });
 4950
 4951            cx.notify();
 4952        });
 4953    }
 4954
 4955    fn trigger_completion_on_input(
 4956        &mut self,
 4957        text: &str,
 4958        trigger_in_words: bool,
 4959        window: &mut Window,
 4960        cx: &mut Context<Self>,
 4961    ) {
 4962        let completions_source = self
 4963            .context_menu
 4964            .borrow()
 4965            .as_ref()
 4966            .and_then(|menu| match menu {
 4967                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4968                CodeContextMenu::CodeActions(_) => None,
 4969            });
 4970
 4971        match completions_source {
 4972            Some(CompletionsMenuSource::Words { .. }) => {
 4973                self.open_or_update_completions_menu(
 4974                    Some(CompletionsMenuSource::Words {
 4975                        ignore_threshold: false,
 4976                    }),
 4977                    None,
 4978                    window,
 4979                    cx,
 4980                );
 4981            }
 4982            Some(CompletionsMenuSource::Normal)
 4983            | Some(CompletionsMenuSource::SnippetChoices)
 4984            | None
 4985                if self.is_completion_trigger(
 4986                    text,
 4987                    trigger_in_words,
 4988                    completions_source.is_some(),
 4989                    cx,
 4990                ) =>
 4991            {
 4992                self.show_completions(
 4993                    &ShowCompletions {
 4994                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4995                    },
 4996                    window,
 4997                    cx,
 4998                )
 4999            }
 5000            _ => {
 5001                self.hide_context_menu(window, cx);
 5002            }
 5003        }
 5004    }
 5005
 5006    fn is_completion_trigger(
 5007        &self,
 5008        text: &str,
 5009        trigger_in_words: bool,
 5010        menu_is_open: bool,
 5011        cx: &mut Context<Self>,
 5012    ) -> bool {
 5013        let position = self.selections.newest_anchor().head();
 5014        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5015            return false;
 5016        };
 5017
 5018        if let Some(completion_provider) = &self.completion_provider {
 5019            completion_provider.is_completion_trigger(
 5020                &buffer,
 5021                position.text_anchor,
 5022                text,
 5023                trigger_in_words,
 5024                menu_is_open,
 5025                cx,
 5026            )
 5027        } else {
 5028            false
 5029        }
 5030    }
 5031
 5032    /// If any empty selections is touching the start of its innermost containing autoclose
 5033    /// region, expand it to select the brackets.
 5034    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5035        let selections = self.selections.all::<usize>(cx);
 5036        let buffer = self.buffer.read(cx).read(cx);
 5037        let new_selections = self
 5038            .selections_with_autoclose_regions(selections, &buffer)
 5039            .map(|(mut selection, region)| {
 5040                if !selection.is_empty() {
 5041                    return selection;
 5042                }
 5043
 5044                if let Some(region) = region {
 5045                    let mut range = region.range.to_offset(&buffer);
 5046                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5047                        range.start -= region.pair.start.len();
 5048                        if buffer.contains_str_at(range.start, &region.pair.start)
 5049                            && buffer.contains_str_at(range.end, &region.pair.end)
 5050                        {
 5051                            range.end += region.pair.end.len();
 5052                            selection.start = range.start;
 5053                            selection.end = range.end;
 5054
 5055                            return selection;
 5056                        }
 5057                    }
 5058                }
 5059
 5060                let always_treat_brackets_as_autoclosed = buffer
 5061                    .language_settings_at(selection.start, cx)
 5062                    .always_treat_brackets_as_autoclosed;
 5063
 5064                if !always_treat_brackets_as_autoclosed {
 5065                    return selection;
 5066                }
 5067
 5068                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5069                    for (pair, enabled) in scope.brackets() {
 5070                        if !enabled || !pair.close {
 5071                            continue;
 5072                        }
 5073
 5074                        if buffer.contains_str_at(selection.start, &pair.end) {
 5075                            let pair_start_len = pair.start.len();
 5076                            if buffer.contains_str_at(
 5077                                selection.start.saturating_sub(pair_start_len),
 5078                                &pair.start,
 5079                            ) {
 5080                                selection.start -= pair_start_len;
 5081                                selection.end += pair.end.len();
 5082
 5083                                return selection;
 5084                            }
 5085                        }
 5086                    }
 5087                }
 5088
 5089                selection
 5090            })
 5091            .collect();
 5092
 5093        drop(buffer);
 5094        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5095            selections.select(new_selections)
 5096        });
 5097    }
 5098
 5099    /// Iterate the given selections, and for each one, find the smallest surrounding
 5100    /// autoclose region. This uses the ordering of the selections and the autoclose
 5101    /// regions to avoid repeated comparisons.
 5102    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5103        &'a self,
 5104        selections: impl IntoIterator<Item = Selection<D>>,
 5105        buffer: &'a MultiBufferSnapshot,
 5106    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5107        let mut i = 0;
 5108        let mut regions = self.autoclose_regions.as_slice();
 5109        selections.into_iter().map(move |selection| {
 5110            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5111
 5112            let mut enclosing = None;
 5113            while let Some(pair_state) = regions.get(i) {
 5114                if pair_state.range.end.to_offset(buffer) < range.start {
 5115                    regions = &regions[i + 1..];
 5116                    i = 0;
 5117                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5118                    break;
 5119                } else {
 5120                    if pair_state.selection_id == selection.id {
 5121                        enclosing = Some(pair_state);
 5122                    }
 5123                    i += 1;
 5124                }
 5125            }
 5126
 5127            (selection, enclosing)
 5128        })
 5129    }
 5130
 5131    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5132    fn invalidate_autoclose_regions(
 5133        &mut self,
 5134        mut selections: &[Selection<Anchor>],
 5135        buffer: &MultiBufferSnapshot,
 5136    ) {
 5137        self.autoclose_regions.retain(|state| {
 5138            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5139                return false;
 5140            }
 5141
 5142            let mut i = 0;
 5143            while let Some(selection) = selections.get(i) {
 5144                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5145                    selections = &selections[1..];
 5146                    continue;
 5147                }
 5148                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5149                    break;
 5150                }
 5151                if selection.id == state.selection_id {
 5152                    return true;
 5153                } else {
 5154                    i += 1;
 5155                }
 5156            }
 5157            false
 5158        });
 5159    }
 5160
 5161    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5162        let offset = position.to_offset(buffer);
 5163        let (word_range, kind) =
 5164            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5165        if offset > word_range.start && kind == Some(CharKind::Word) {
 5166            Some(
 5167                buffer
 5168                    .text_for_range(word_range.start..offset)
 5169                    .collect::<String>(),
 5170            )
 5171        } else {
 5172            None
 5173        }
 5174    }
 5175
 5176    pub fn toggle_inline_values(
 5177        &mut self,
 5178        _: &ToggleInlineValues,
 5179        _: &mut Window,
 5180        cx: &mut Context<Self>,
 5181    ) {
 5182        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5183
 5184        self.refresh_inline_values(cx);
 5185    }
 5186
 5187    pub fn toggle_inlay_hints(
 5188        &mut self,
 5189        _: &ToggleInlayHints,
 5190        _: &mut Window,
 5191        cx: &mut Context<Self>,
 5192    ) {
 5193        self.refresh_inlay_hints(
 5194            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5195            cx,
 5196        );
 5197    }
 5198
 5199    pub fn inlay_hints_enabled(&self) -> bool {
 5200        self.inlay_hint_cache.enabled
 5201    }
 5202
 5203    pub fn inline_values_enabled(&self) -> bool {
 5204        self.inline_value_cache.enabled
 5205    }
 5206
 5207    #[cfg(any(test, feature = "test-support"))]
 5208    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5209        self.display_map
 5210            .read(cx)
 5211            .current_inlays()
 5212            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5213            .cloned()
 5214            .collect()
 5215    }
 5216
 5217    #[cfg(any(test, feature = "test-support"))]
 5218    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5219        self.display_map
 5220            .read(cx)
 5221            .current_inlays()
 5222            .cloned()
 5223            .collect()
 5224    }
 5225
 5226    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5227        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5228            return;
 5229        }
 5230
 5231        let reason_description = reason.description();
 5232        let ignore_debounce = matches!(
 5233            reason,
 5234            InlayHintRefreshReason::SettingsChange(_)
 5235                | InlayHintRefreshReason::Toggle(_)
 5236                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5237                | InlayHintRefreshReason::ModifiersChanged(_)
 5238        );
 5239        let (invalidate_cache, required_languages) = match reason {
 5240            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5241                match self.inlay_hint_cache.modifiers_override(enabled) {
 5242                    Some(enabled) => {
 5243                        if enabled {
 5244                            (InvalidationStrategy::RefreshRequested, None)
 5245                        } else {
 5246                            self.splice_inlays(
 5247                                &self
 5248                                    .visible_inlay_hints(cx)
 5249                                    .iter()
 5250                                    .map(|inlay| inlay.id)
 5251                                    .collect::<Vec<InlayId>>(),
 5252                                Vec::new(),
 5253                                cx,
 5254                            );
 5255                            return;
 5256                        }
 5257                    }
 5258                    None => return,
 5259                }
 5260            }
 5261            InlayHintRefreshReason::Toggle(enabled) => {
 5262                if self.inlay_hint_cache.toggle(enabled) {
 5263                    if enabled {
 5264                        (InvalidationStrategy::RefreshRequested, None)
 5265                    } else {
 5266                        self.splice_inlays(
 5267                            &self
 5268                                .visible_inlay_hints(cx)
 5269                                .iter()
 5270                                .map(|inlay| inlay.id)
 5271                                .collect::<Vec<InlayId>>(),
 5272                            Vec::new(),
 5273                            cx,
 5274                        );
 5275                        return;
 5276                    }
 5277                } else {
 5278                    return;
 5279                }
 5280            }
 5281            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5282                match self.inlay_hint_cache.update_settings(
 5283                    &self.buffer,
 5284                    new_settings,
 5285                    self.visible_inlay_hints(cx),
 5286                    cx,
 5287                ) {
 5288                    ControlFlow::Break(Some(InlaySplice {
 5289                        to_remove,
 5290                        to_insert,
 5291                    })) => {
 5292                        self.splice_inlays(&to_remove, to_insert, cx);
 5293                        return;
 5294                    }
 5295                    ControlFlow::Break(None) => return,
 5296                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5297                }
 5298            }
 5299            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5300                if let Some(InlaySplice {
 5301                    to_remove,
 5302                    to_insert,
 5303                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5304                {
 5305                    self.splice_inlays(&to_remove, to_insert, cx);
 5306                }
 5307                self.display_map.update(cx, |display_map, _| {
 5308                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5309                });
 5310                return;
 5311            }
 5312            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5313            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5314                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5315            }
 5316            InlayHintRefreshReason::RefreshRequested => {
 5317                (InvalidationStrategy::RefreshRequested, None)
 5318            }
 5319        };
 5320
 5321        if let Some(InlaySplice {
 5322            to_remove,
 5323            to_insert,
 5324        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5325            reason_description,
 5326            self.visible_excerpts(required_languages.as_ref(), cx),
 5327            invalidate_cache,
 5328            ignore_debounce,
 5329            cx,
 5330        ) {
 5331            self.splice_inlays(&to_remove, to_insert, cx);
 5332        }
 5333    }
 5334
 5335    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5336        self.display_map
 5337            .read(cx)
 5338            .current_inlays()
 5339            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5340            .cloned()
 5341            .collect()
 5342    }
 5343
 5344    pub fn visible_excerpts(
 5345        &self,
 5346        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5347        cx: &mut Context<Editor>,
 5348    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5349        let Some(project) = self.project() else {
 5350            return HashMap::default();
 5351        };
 5352        let project = project.read(cx);
 5353        let multi_buffer = self.buffer().read(cx);
 5354        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5355        let multi_buffer_visible_start = self
 5356            .scroll_manager
 5357            .anchor()
 5358            .anchor
 5359            .to_point(&multi_buffer_snapshot);
 5360        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5361            multi_buffer_visible_start
 5362                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5363            Bias::Left,
 5364        );
 5365        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5366        multi_buffer_snapshot
 5367            .range_to_buffer_ranges(multi_buffer_visible_range)
 5368            .into_iter()
 5369            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5370            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5371                let buffer_file = project::File::from_dyn(buffer.file())?;
 5372                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5373                let worktree_entry = buffer_worktree
 5374                    .read(cx)
 5375                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5376                if worktree_entry.is_ignored {
 5377                    return None;
 5378                }
 5379
 5380                let language = buffer.language()?;
 5381                if let Some(restrict_to_languages) = restrict_to_languages
 5382                    && !restrict_to_languages.contains(language)
 5383                {
 5384                    return None;
 5385                }
 5386                Some((
 5387                    excerpt_id,
 5388                    (
 5389                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5390                        buffer.version().clone(),
 5391                        excerpt_visible_range,
 5392                    ),
 5393                ))
 5394            })
 5395            .collect()
 5396    }
 5397
 5398    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5399        TextLayoutDetails {
 5400            text_system: window.text_system().clone(),
 5401            editor_style: self.style.clone().unwrap(),
 5402            rem_size: window.rem_size(),
 5403            scroll_anchor: self.scroll_manager.anchor(),
 5404            visible_rows: self.visible_line_count(),
 5405            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5406        }
 5407    }
 5408
 5409    pub fn splice_inlays(
 5410        &self,
 5411        to_remove: &[InlayId],
 5412        to_insert: Vec<Inlay>,
 5413        cx: &mut Context<Self>,
 5414    ) {
 5415        self.display_map.update(cx, |display_map, cx| {
 5416            display_map.splice_inlays(to_remove, to_insert, cx)
 5417        });
 5418        cx.notify();
 5419    }
 5420
 5421    fn trigger_on_type_formatting(
 5422        &self,
 5423        input: String,
 5424        window: &mut Window,
 5425        cx: &mut Context<Self>,
 5426    ) -> Option<Task<Result<()>>> {
 5427        if input.len() != 1 {
 5428            return None;
 5429        }
 5430
 5431        let project = self.project()?;
 5432        let position = self.selections.newest_anchor().head();
 5433        let (buffer, buffer_position) = self
 5434            .buffer
 5435            .read(cx)
 5436            .text_anchor_for_position(position, cx)?;
 5437
 5438        let settings = language_settings::language_settings(
 5439            buffer
 5440                .read(cx)
 5441                .language_at(buffer_position)
 5442                .map(|l| l.name()),
 5443            buffer.read(cx).file(),
 5444            cx,
 5445        );
 5446        if !settings.use_on_type_format {
 5447            return None;
 5448        }
 5449
 5450        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5451        // hence we do LSP request & edit on host side only — add formats to host's history.
 5452        let push_to_lsp_host_history = true;
 5453        // If this is not the host, append its history with new edits.
 5454        let push_to_client_history = project.read(cx).is_via_collab();
 5455
 5456        let on_type_formatting = project.update(cx, |project, cx| {
 5457            project.on_type_format(
 5458                buffer.clone(),
 5459                buffer_position,
 5460                input,
 5461                push_to_lsp_host_history,
 5462                cx,
 5463            )
 5464        });
 5465        Some(cx.spawn_in(window, async move |editor, cx| {
 5466            if let Some(transaction) = on_type_formatting.await? {
 5467                if push_to_client_history {
 5468                    buffer
 5469                        .update(cx, |buffer, _| {
 5470                            buffer.push_transaction(transaction, Instant::now());
 5471                            buffer.finalize_last_transaction();
 5472                        })
 5473                        .ok();
 5474                }
 5475                editor.update(cx, |editor, cx| {
 5476                    editor.refresh_document_highlights(cx);
 5477                })?;
 5478            }
 5479            Ok(())
 5480        }))
 5481    }
 5482
 5483    pub fn show_word_completions(
 5484        &mut self,
 5485        _: &ShowWordCompletions,
 5486        window: &mut Window,
 5487        cx: &mut Context<Self>,
 5488    ) {
 5489        self.open_or_update_completions_menu(
 5490            Some(CompletionsMenuSource::Words {
 5491                ignore_threshold: true,
 5492            }),
 5493            None,
 5494            window,
 5495            cx,
 5496        );
 5497    }
 5498
 5499    pub fn show_completions(
 5500        &mut self,
 5501        options: &ShowCompletions,
 5502        window: &mut Window,
 5503        cx: &mut Context<Self>,
 5504    ) {
 5505        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5506    }
 5507
 5508    fn open_or_update_completions_menu(
 5509        &mut self,
 5510        requested_source: Option<CompletionsMenuSource>,
 5511        trigger: Option<&str>,
 5512        window: &mut Window,
 5513        cx: &mut Context<Self>,
 5514    ) {
 5515        if self.pending_rename.is_some() {
 5516            return;
 5517        }
 5518
 5519        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5520
 5521        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5522        // inserted and selected. To handle that case, the start of the selection is used so that
 5523        // the menu starts with all choices.
 5524        let position = self
 5525            .selections
 5526            .newest_anchor()
 5527            .start
 5528            .bias_right(&multibuffer_snapshot);
 5529        if position.diff_base_anchor.is_some() {
 5530            return;
 5531        }
 5532        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5533        let Some(buffer) = buffer_position
 5534            .buffer_id
 5535            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5536        else {
 5537            return;
 5538        };
 5539        let buffer_snapshot = buffer.read(cx).snapshot();
 5540
 5541        let query: Option<Arc<String>> =
 5542            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5543                .map(|query| query.into());
 5544
 5545        drop(multibuffer_snapshot);
 5546
 5547        // Hide the current completions menu when query is empty. Without this, cached
 5548        // completions from before the trigger char may be reused (#32774).
 5549        if query.is_none() {
 5550            let menu_is_open = matches!(
 5551                self.context_menu.borrow().as_ref(),
 5552                Some(CodeContextMenu::Completions(_))
 5553            );
 5554            if menu_is_open {
 5555                self.hide_context_menu(window, cx);
 5556            }
 5557        }
 5558
 5559        let mut ignore_word_threshold = false;
 5560        let provider = match requested_source {
 5561            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5562            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5563                ignore_word_threshold = ignore_threshold;
 5564                None
 5565            }
 5566            Some(CompletionsMenuSource::SnippetChoices) => {
 5567                log::error!("bug: SnippetChoices requested_source is not handled");
 5568                None
 5569            }
 5570        };
 5571
 5572        let sort_completions = provider
 5573            .as_ref()
 5574            .is_some_and(|provider| provider.sort_completions());
 5575
 5576        let filter_completions = provider
 5577            .as_ref()
 5578            .is_none_or(|provider| provider.filter_completions());
 5579
 5580        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5581            if filter_completions {
 5582                menu.filter(query.clone(), provider.clone(), window, cx);
 5583            }
 5584            // When `is_incomplete` is false, no need to re-query completions when the current query
 5585            // is a suffix of the initial query.
 5586            if !menu.is_incomplete {
 5587                // If the new query is a suffix of the old query (typing more characters) and
 5588                // the previous result was complete, the existing completions can be filtered.
 5589                //
 5590                // Note that this is always true for snippet completions.
 5591                let query_matches = match (&menu.initial_query, &query) {
 5592                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5593                    (None, _) => true,
 5594                    _ => false,
 5595                };
 5596                if query_matches {
 5597                    let position_matches = if menu.initial_position == position {
 5598                        true
 5599                    } else {
 5600                        let snapshot = self.buffer.read(cx).read(cx);
 5601                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5602                    };
 5603                    if position_matches {
 5604                        return;
 5605                    }
 5606                }
 5607            }
 5608        };
 5609
 5610        let trigger_kind = match trigger {
 5611            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5612                CompletionTriggerKind::TRIGGER_CHARACTER
 5613            }
 5614            _ => CompletionTriggerKind::INVOKED,
 5615        };
 5616        let completion_context = CompletionContext {
 5617            trigger_character: trigger.and_then(|trigger| {
 5618                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5619                    Some(String::from(trigger))
 5620                } else {
 5621                    None
 5622                }
 5623            }),
 5624            trigger_kind,
 5625        };
 5626
 5627        let Anchor {
 5628            excerpt_id: buffer_excerpt_id,
 5629            text_anchor: buffer_position,
 5630            ..
 5631        } = buffer_position;
 5632
 5633        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5634            buffer_snapshot.surrounding_word(buffer_position, None)
 5635        {
 5636            let word_to_exclude = buffer_snapshot
 5637                .text_for_range(word_range.clone())
 5638                .collect::<String>();
 5639            (
 5640                buffer_snapshot.anchor_before(word_range.start)
 5641                    ..buffer_snapshot.anchor_after(buffer_position),
 5642                Some(word_to_exclude),
 5643            )
 5644        } else {
 5645            (buffer_position..buffer_position, None)
 5646        };
 5647
 5648        let language = buffer_snapshot
 5649            .language_at(buffer_position)
 5650            .map(|language| language.name());
 5651
 5652        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5653            .completions
 5654            .clone();
 5655
 5656        let show_completion_documentation = buffer_snapshot
 5657            .settings_at(buffer_position, cx)
 5658            .show_completion_documentation;
 5659
 5660        // The document can be large, so stay in reasonable bounds when searching for words,
 5661        // otherwise completion pop-up might be slow to appear.
 5662        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5663        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5664        let min_word_search = buffer_snapshot.clip_point(
 5665            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5666            Bias::Left,
 5667        );
 5668        let max_word_search = buffer_snapshot.clip_point(
 5669            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5670            Bias::Right,
 5671        );
 5672        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5673            ..buffer_snapshot.point_to_offset(max_word_search);
 5674
 5675        let skip_digits = query
 5676            .as_ref()
 5677            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5678
 5679        let omit_word_completions = !self.word_completions_enabled
 5680            || (!ignore_word_threshold
 5681                && match &query {
 5682                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5683                    None => completion_settings.words_min_length != 0,
 5684                });
 5685
 5686        let (mut words, provider_responses) = match &provider {
 5687            Some(provider) => {
 5688                let provider_responses = provider.completions(
 5689                    buffer_excerpt_id,
 5690                    &buffer,
 5691                    buffer_position,
 5692                    completion_context,
 5693                    window,
 5694                    cx,
 5695                );
 5696
 5697                let words = match (omit_word_completions, completion_settings.words) {
 5698                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5699                        Task::ready(BTreeMap::default())
 5700                    }
 5701                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5702                        .background_spawn(async move {
 5703                            buffer_snapshot.words_in_range(WordsQuery {
 5704                                fuzzy_contents: None,
 5705                                range: word_search_range,
 5706                                skip_digits,
 5707                            })
 5708                        }),
 5709                };
 5710
 5711                (words, provider_responses)
 5712            }
 5713            None => {
 5714                let words = if omit_word_completions {
 5715                    Task::ready(BTreeMap::default())
 5716                } else {
 5717                    cx.background_spawn(async move {
 5718                        buffer_snapshot.words_in_range(WordsQuery {
 5719                            fuzzy_contents: None,
 5720                            range: word_search_range,
 5721                            skip_digits,
 5722                        })
 5723                    })
 5724                };
 5725                (words, Task::ready(Ok(Vec::new())))
 5726            }
 5727        };
 5728
 5729        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5730
 5731        let id = post_inc(&mut self.next_completion_id);
 5732        let task = cx.spawn_in(window, async move |editor, cx| {
 5733            let Ok(()) = editor.update(cx, |this, _| {
 5734                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5735            }) else {
 5736                return;
 5737            };
 5738
 5739            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5740            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5741            let mut completions = Vec::new();
 5742            let mut is_incomplete = false;
 5743            let mut display_options: Option<CompletionDisplayOptions> = None;
 5744            if let Some(provider_responses) = provider_responses.await.log_err()
 5745                && !provider_responses.is_empty()
 5746            {
 5747                for response in provider_responses {
 5748                    completions.extend(response.completions);
 5749                    is_incomplete = is_incomplete || response.is_incomplete;
 5750                    match display_options.as_mut() {
 5751                        None => {
 5752                            display_options = Some(response.display_options);
 5753                        }
 5754                        Some(options) => options.merge(&response.display_options),
 5755                    }
 5756                }
 5757                if completion_settings.words == WordsCompletionMode::Fallback {
 5758                    words = Task::ready(BTreeMap::default());
 5759                }
 5760            }
 5761            let display_options = display_options.unwrap_or_default();
 5762
 5763            let mut words = words.await;
 5764            if let Some(word_to_exclude) = &word_to_exclude {
 5765                words.remove(word_to_exclude);
 5766            }
 5767            for lsp_completion in &completions {
 5768                words.remove(&lsp_completion.new_text);
 5769            }
 5770            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5771                replace_range: word_replace_range.clone(),
 5772                new_text: word.clone(),
 5773                label: CodeLabel::plain(word, None),
 5774                icon_path: None,
 5775                documentation: None,
 5776                source: CompletionSource::BufferWord {
 5777                    word_range,
 5778                    resolved: false,
 5779                },
 5780                insert_text_mode: Some(InsertTextMode::AS_IS),
 5781                confirm: None,
 5782            }));
 5783
 5784            let menu = if completions.is_empty() {
 5785                None
 5786            } else {
 5787                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5788                    let languages = editor
 5789                        .workspace
 5790                        .as_ref()
 5791                        .and_then(|(workspace, _)| workspace.upgrade())
 5792                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5793                    let menu = CompletionsMenu::new(
 5794                        id,
 5795                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5796                        sort_completions,
 5797                        show_completion_documentation,
 5798                        position,
 5799                        query.clone(),
 5800                        is_incomplete,
 5801                        buffer.clone(),
 5802                        completions.into(),
 5803                        display_options,
 5804                        snippet_sort_order,
 5805                        languages,
 5806                        language,
 5807                        cx,
 5808                    );
 5809
 5810                    let query = if filter_completions { query } else { None };
 5811                    let matches_task = if let Some(query) = query {
 5812                        menu.do_async_filtering(query, cx)
 5813                    } else {
 5814                        Task::ready(menu.unfiltered_matches())
 5815                    };
 5816                    (menu, matches_task)
 5817                }) else {
 5818                    return;
 5819                };
 5820
 5821                let matches = matches_task.await;
 5822
 5823                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5824                    // Newer menu already set, so exit.
 5825                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5826                        editor.context_menu.borrow().as_ref()
 5827                        && prev_menu.id > id
 5828                    {
 5829                        return;
 5830                    };
 5831
 5832                    // Only valid to take prev_menu because it the new menu is immediately set
 5833                    // below, or the menu is hidden.
 5834                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5835                        editor.context_menu.borrow_mut().take()
 5836                    {
 5837                        let position_matches =
 5838                            if prev_menu.initial_position == menu.initial_position {
 5839                                true
 5840                            } else {
 5841                                let snapshot = editor.buffer.read(cx).read(cx);
 5842                                prev_menu.initial_position.to_offset(&snapshot)
 5843                                    == menu.initial_position.to_offset(&snapshot)
 5844                            };
 5845                        if position_matches {
 5846                            // Preserve markdown cache before `set_filter_results` because it will
 5847                            // try to populate the documentation cache.
 5848                            menu.preserve_markdown_cache(prev_menu);
 5849                        }
 5850                    };
 5851
 5852                    menu.set_filter_results(matches, provider, window, cx);
 5853                }) else {
 5854                    return;
 5855                };
 5856
 5857                menu.visible().then_some(menu)
 5858            };
 5859
 5860            editor
 5861                .update_in(cx, |editor, window, cx| {
 5862                    if editor.focus_handle.is_focused(window)
 5863                        && let Some(menu) = menu
 5864                    {
 5865                        *editor.context_menu.borrow_mut() =
 5866                            Some(CodeContextMenu::Completions(menu));
 5867
 5868                        crate::hover_popover::hide_hover(editor, cx);
 5869                        if editor.show_edit_predictions_in_menu() {
 5870                            editor.update_visible_edit_prediction(window, cx);
 5871                        } else {
 5872                            editor.discard_edit_prediction(false, cx);
 5873                        }
 5874
 5875                        cx.notify();
 5876                        return;
 5877                    }
 5878
 5879                    if editor.completion_tasks.len() <= 1 {
 5880                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5881                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5882                        // If it was already hidden and we don't show edit predictions in the menu,
 5883                        // we should also show the edit prediction when available.
 5884                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5885                            editor.update_visible_edit_prediction(window, cx);
 5886                        }
 5887                    }
 5888                })
 5889                .ok();
 5890        });
 5891
 5892        self.completion_tasks.push((id, task));
 5893    }
 5894
 5895    #[cfg(feature = "test-support")]
 5896    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5897        let menu = self.context_menu.borrow();
 5898        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5899            let completions = menu.completions.borrow();
 5900            Some(completions.to_vec())
 5901        } else {
 5902            None
 5903        }
 5904    }
 5905
 5906    pub fn with_completions_menu_matching_id<R>(
 5907        &self,
 5908        id: CompletionId,
 5909        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5910    ) -> R {
 5911        let mut context_menu = self.context_menu.borrow_mut();
 5912        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5913            return f(None);
 5914        };
 5915        if completions_menu.id != id {
 5916            return f(None);
 5917        }
 5918        f(Some(completions_menu))
 5919    }
 5920
 5921    pub fn confirm_completion(
 5922        &mut self,
 5923        action: &ConfirmCompletion,
 5924        window: &mut Window,
 5925        cx: &mut Context<Self>,
 5926    ) -> Option<Task<Result<()>>> {
 5927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5928        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5929    }
 5930
 5931    pub fn confirm_completion_insert(
 5932        &mut self,
 5933        _: &ConfirmCompletionInsert,
 5934        window: &mut Window,
 5935        cx: &mut Context<Self>,
 5936    ) -> Option<Task<Result<()>>> {
 5937        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5938        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5939    }
 5940
 5941    pub fn confirm_completion_replace(
 5942        &mut self,
 5943        _: &ConfirmCompletionReplace,
 5944        window: &mut Window,
 5945        cx: &mut Context<Self>,
 5946    ) -> Option<Task<Result<()>>> {
 5947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5948        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5949    }
 5950
 5951    pub fn compose_completion(
 5952        &mut self,
 5953        action: &ComposeCompletion,
 5954        window: &mut Window,
 5955        cx: &mut Context<Self>,
 5956    ) -> Option<Task<Result<()>>> {
 5957        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5958        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5959    }
 5960
 5961    fn do_completion(
 5962        &mut self,
 5963        item_ix: Option<usize>,
 5964        intent: CompletionIntent,
 5965        window: &mut Window,
 5966        cx: &mut Context<Editor>,
 5967    ) -> Option<Task<Result<()>>> {
 5968        use language::ToOffset as _;
 5969
 5970        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5971        else {
 5972            return None;
 5973        };
 5974
 5975        let candidate_id = {
 5976            let entries = completions_menu.entries.borrow();
 5977            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5978            if self.show_edit_predictions_in_menu() {
 5979                self.discard_edit_prediction(true, cx);
 5980            }
 5981            mat.candidate_id
 5982        };
 5983
 5984        let completion = completions_menu
 5985            .completions
 5986            .borrow()
 5987            .get(candidate_id)?
 5988            .clone();
 5989        cx.stop_propagation();
 5990
 5991        let buffer_handle = completions_menu.buffer.clone();
 5992
 5993        let CompletionEdit {
 5994            new_text,
 5995            snippet,
 5996            replace_range,
 5997        } = process_completion_for_edit(
 5998            &completion,
 5999            intent,
 6000            &buffer_handle,
 6001            &completions_menu.initial_position.text_anchor,
 6002            cx,
 6003        );
 6004
 6005        let buffer = buffer_handle.read(cx);
 6006        let snapshot = self.buffer.read(cx).snapshot(cx);
 6007        let newest_anchor = self.selections.newest_anchor();
 6008        let replace_range_multibuffer = {
 6009            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6010            let multibuffer_anchor = snapshot
 6011                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 6012                .unwrap()
 6013                ..snapshot
 6014                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 6015                    .unwrap();
 6016            multibuffer_anchor.start.to_offset(&snapshot)
 6017                ..multibuffer_anchor.end.to_offset(&snapshot)
 6018        };
 6019        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6020            return None;
 6021        }
 6022
 6023        let old_text = buffer
 6024            .text_for_range(replace_range.clone())
 6025            .collect::<String>();
 6026        let lookbehind = newest_anchor
 6027            .start
 6028            .text_anchor
 6029            .to_offset(buffer)
 6030            .saturating_sub(replace_range.start);
 6031        let lookahead = replace_range
 6032            .end
 6033            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6034        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6035        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6036
 6037        let selections = self.selections.all::<usize>(cx);
 6038        let mut ranges = Vec::new();
 6039        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6040
 6041        for selection in &selections {
 6042            let range = if selection.id == newest_anchor.id {
 6043                replace_range_multibuffer.clone()
 6044            } else {
 6045                let mut range = selection.range();
 6046
 6047                // if prefix is present, don't duplicate it
 6048                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6049                    range.start = range.start.saturating_sub(lookbehind);
 6050
 6051                    // if suffix is also present, mimic the newest cursor and replace it
 6052                    if selection.id != newest_anchor.id
 6053                        && snapshot.contains_str_at(range.end, suffix)
 6054                    {
 6055                        range.end += lookahead;
 6056                    }
 6057                }
 6058                range
 6059            };
 6060
 6061            ranges.push(range.clone());
 6062
 6063            if !self.linked_edit_ranges.is_empty() {
 6064                let start_anchor = snapshot.anchor_before(range.start);
 6065                let end_anchor = snapshot.anchor_after(range.end);
 6066                if let Some(ranges) = self
 6067                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6068                {
 6069                    for (buffer, edits) in ranges {
 6070                        linked_edits
 6071                            .entry(buffer.clone())
 6072                            .or_default()
 6073                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6074                    }
 6075                }
 6076            }
 6077        }
 6078
 6079        let common_prefix_len = old_text
 6080            .chars()
 6081            .zip(new_text.chars())
 6082            .take_while(|(a, b)| a == b)
 6083            .map(|(a, _)| a.len_utf8())
 6084            .sum::<usize>();
 6085
 6086        cx.emit(EditorEvent::InputHandled {
 6087            utf16_range_to_replace: None,
 6088            text: new_text[common_prefix_len..].into(),
 6089        });
 6090
 6091        self.transact(window, cx, |editor, window, cx| {
 6092            if let Some(mut snippet) = snippet {
 6093                snippet.text = new_text.to_string();
 6094                editor
 6095                    .insert_snippet(&ranges, snippet, window, cx)
 6096                    .log_err();
 6097            } else {
 6098                editor.buffer.update(cx, |multi_buffer, cx| {
 6099                    let auto_indent = match completion.insert_text_mode {
 6100                        Some(InsertTextMode::AS_IS) => None,
 6101                        _ => editor.autoindent_mode.clone(),
 6102                    };
 6103                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6104                    multi_buffer.edit(edits, auto_indent, cx);
 6105                });
 6106            }
 6107            for (buffer, edits) in linked_edits {
 6108                buffer.update(cx, |buffer, cx| {
 6109                    let snapshot = buffer.snapshot();
 6110                    let edits = edits
 6111                        .into_iter()
 6112                        .map(|(range, text)| {
 6113                            use text::ToPoint as TP;
 6114                            let end_point = TP::to_point(&range.end, &snapshot);
 6115                            let start_point = TP::to_point(&range.start, &snapshot);
 6116                            (start_point..end_point, text)
 6117                        })
 6118                        .sorted_by_key(|(range, _)| range.start);
 6119                    buffer.edit(edits, None, cx);
 6120                })
 6121            }
 6122
 6123            editor.refresh_edit_prediction(true, false, window, cx);
 6124        });
 6125        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6126
 6127        let show_new_completions_on_confirm = completion
 6128            .confirm
 6129            .as_ref()
 6130            .is_some_and(|confirm| confirm(intent, window, cx));
 6131        if show_new_completions_on_confirm {
 6132            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6133        }
 6134
 6135        let provider = self.completion_provider.as_ref()?;
 6136        drop(completion);
 6137        let apply_edits = provider.apply_additional_edits_for_completion(
 6138            buffer_handle,
 6139            completions_menu.completions.clone(),
 6140            candidate_id,
 6141            true,
 6142            cx,
 6143        );
 6144
 6145        let editor_settings = EditorSettings::get_global(cx);
 6146        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6147            // After the code completion is finished, users often want to know what signatures are needed.
 6148            // so we should automatically call signature_help
 6149            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6150        }
 6151
 6152        Some(cx.foreground_executor().spawn(async move {
 6153            apply_edits.await?;
 6154            Ok(())
 6155        }))
 6156    }
 6157
 6158    pub fn toggle_code_actions(
 6159        &mut self,
 6160        action: &ToggleCodeActions,
 6161        window: &mut Window,
 6162        cx: &mut Context<Self>,
 6163    ) {
 6164        let quick_launch = action.quick_launch;
 6165        let mut context_menu = self.context_menu.borrow_mut();
 6166        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6167            if code_actions.deployed_from == action.deployed_from {
 6168                // Toggle if we're selecting the same one
 6169                *context_menu = None;
 6170                cx.notify();
 6171                return;
 6172            } else {
 6173                // Otherwise, clear it and start a new one
 6174                *context_menu = None;
 6175                cx.notify();
 6176            }
 6177        }
 6178        drop(context_menu);
 6179        let snapshot = self.snapshot(window, cx);
 6180        let deployed_from = action.deployed_from.clone();
 6181        let action = action.clone();
 6182        self.completion_tasks.clear();
 6183        self.discard_edit_prediction(false, cx);
 6184
 6185        let multibuffer_point = match &action.deployed_from {
 6186            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6187                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6188            }
 6189            _ => self.selections.newest::<Point>(cx).head(),
 6190        };
 6191        let Some((buffer, buffer_row)) = snapshot
 6192            .buffer_snapshot()
 6193            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6194            .and_then(|(buffer_snapshot, range)| {
 6195                self.buffer()
 6196                    .read(cx)
 6197                    .buffer(buffer_snapshot.remote_id())
 6198                    .map(|buffer| (buffer, range.start.row))
 6199            })
 6200        else {
 6201            return;
 6202        };
 6203        let buffer_id = buffer.read(cx).remote_id();
 6204        let tasks = self
 6205            .tasks
 6206            .get(&(buffer_id, buffer_row))
 6207            .map(|t| Arc::new(t.to_owned()));
 6208
 6209        if !self.focus_handle.is_focused(window) {
 6210            return;
 6211        }
 6212        let project = self.project.clone();
 6213
 6214        let code_actions_task = match deployed_from {
 6215            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6216            _ => self.code_actions(buffer_row, window, cx),
 6217        };
 6218
 6219        let runnable_task = match deployed_from {
 6220            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6221            _ => {
 6222                let mut task_context_task = Task::ready(None);
 6223                if let Some(tasks) = &tasks
 6224                    && let Some(project) = project
 6225                {
 6226                    task_context_task =
 6227                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6228                }
 6229
 6230                cx.spawn_in(window, {
 6231                    let buffer = buffer.clone();
 6232                    async move |editor, cx| {
 6233                        let task_context = task_context_task.await;
 6234
 6235                        let resolved_tasks =
 6236                            tasks
 6237                                .zip(task_context.clone())
 6238                                .map(|(tasks, task_context)| ResolvedTasks {
 6239                                    templates: tasks.resolve(&task_context).collect(),
 6240                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6241                                        multibuffer_point.row,
 6242                                        tasks.column,
 6243                                    )),
 6244                                });
 6245                        let debug_scenarios = editor
 6246                            .update(cx, |editor, cx| {
 6247                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6248                            })?
 6249                            .await;
 6250                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6251                    }
 6252                })
 6253            }
 6254        };
 6255
 6256        cx.spawn_in(window, async move |editor, cx| {
 6257            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6258            let code_actions = code_actions_task.await;
 6259            let spawn_straight_away = quick_launch
 6260                && resolved_tasks
 6261                    .as_ref()
 6262                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6263                && code_actions
 6264                    .as_ref()
 6265                    .is_none_or(|actions| actions.is_empty())
 6266                && debug_scenarios.is_empty();
 6267
 6268            editor.update_in(cx, |editor, window, cx| {
 6269                crate::hover_popover::hide_hover(editor, cx);
 6270                let actions = CodeActionContents::new(
 6271                    resolved_tasks,
 6272                    code_actions,
 6273                    debug_scenarios,
 6274                    task_context.unwrap_or_default(),
 6275                );
 6276
 6277                // Don't show the menu if there are no actions available
 6278                if actions.is_empty() {
 6279                    cx.notify();
 6280                    return Task::ready(Ok(()));
 6281                }
 6282
 6283                *editor.context_menu.borrow_mut() =
 6284                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6285                        buffer,
 6286                        actions,
 6287                        selected_item: Default::default(),
 6288                        scroll_handle: UniformListScrollHandle::default(),
 6289                        deployed_from,
 6290                    }));
 6291                cx.notify();
 6292                if spawn_straight_away
 6293                    && let Some(task) = editor.confirm_code_action(
 6294                        &ConfirmCodeAction { item_ix: Some(0) },
 6295                        window,
 6296                        cx,
 6297                    )
 6298                {
 6299                    return task;
 6300                }
 6301
 6302                Task::ready(Ok(()))
 6303            })
 6304        })
 6305        .detach_and_log_err(cx);
 6306    }
 6307
 6308    fn debug_scenarios(
 6309        &mut self,
 6310        resolved_tasks: &Option<ResolvedTasks>,
 6311        buffer: &Entity<Buffer>,
 6312        cx: &mut App,
 6313    ) -> Task<Vec<task::DebugScenario>> {
 6314        maybe!({
 6315            let project = self.project()?;
 6316            let dap_store = project.read(cx).dap_store();
 6317            let mut scenarios = vec![];
 6318            let resolved_tasks = resolved_tasks.as_ref()?;
 6319            let buffer = buffer.read(cx);
 6320            let language = buffer.language()?;
 6321            let file = buffer.file();
 6322            let debug_adapter = language_settings(language.name().into(), file, cx)
 6323                .debuggers
 6324                .first()
 6325                .map(SharedString::from)
 6326                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6327
 6328            dap_store.update(cx, |dap_store, cx| {
 6329                for (_, task) in &resolved_tasks.templates {
 6330                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6331                        task.original_task().clone(),
 6332                        debug_adapter.clone().into(),
 6333                        task.display_label().to_owned().into(),
 6334                        cx,
 6335                    );
 6336                    scenarios.push(maybe_scenario);
 6337                }
 6338            });
 6339            Some(cx.background_spawn(async move {
 6340                futures::future::join_all(scenarios)
 6341                    .await
 6342                    .into_iter()
 6343                    .flatten()
 6344                    .collect::<Vec<_>>()
 6345            }))
 6346        })
 6347        .unwrap_or_else(|| Task::ready(vec![]))
 6348    }
 6349
 6350    fn code_actions(
 6351        &mut self,
 6352        buffer_row: u32,
 6353        window: &mut Window,
 6354        cx: &mut Context<Self>,
 6355    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6356        let mut task = self.code_actions_task.take();
 6357        cx.spawn_in(window, async move |editor, cx| {
 6358            while let Some(prev_task) = task {
 6359                prev_task.await.log_err();
 6360                task = editor
 6361                    .update(cx, |this, _| this.code_actions_task.take())
 6362                    .ok()?;
 6363            }
 6364
 6365            editor
 6366                .update(cx, |editor, cx| {
 6367                    editor
 6368                        .available_code_actions
 6369                        .clone()
 6370                        .and_then(|(location, code_actions)| {
 6371                            let snapshot = location.buffer.read(cx).snapshot();
 6372                            let point_range = location.range.to_point(&snapshot);
 6373                            let point_range = point_range.start.row..=point_range.end.row;
 6374                            if point_range.contains(&buffer_row) {
 6375                                Some(code_actions)
 6376                            } else {
 6377                                None
 6378                            }
 6379                        })
 6380                })
 6381                .ok()
 6382                .flatten()
 6383        })
 6384    }
 6385
 6386    pub fn confirm_code_action(
 6387        &mut self,
 6388        action: &ConfirmCodeAction,
 6389        window: &mut Window,
 6390        cx: &mut Context<Self>,
 6391    ) -> Option<Task<Result<()>>> {
 6392        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6393
 6394        let actions_menu =
 6395            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6396                menu
 6397            } else {
 6398                return None;
 6399            };
 6400
 6401        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6402        let action = actions_menu.actions.get(action_ix)?;
 6403        let title = action.label();
 6404        let buffer = actions_menu.buffer;
 6405        let workspace = self.workspace()?;
 6406
 6407        match action {
 6408            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6409                workspace.update(cx, |workspace, cx| {
 6410                    workspace.schedule_resolved_task(
 6411                        task_source_kind,
 6412                        resolved_task,
 6413                        false,
 6414                        window,
 6415                        cx,
 6416                    );
 6417
 6418                    Some(Task::ready(Ok(())))
 6419                })
 6420            }
 6421            CodeActionsItem::CodeAction {
 6422                excerpt_id,
 6423                action,
 6424                provider,
 6425            } => {
 6426                let apply_code_action =
 6427                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6428                let workspace = workspace.downgrade();
 6429                Some(cx.spawn_in(window, async move |editor, cx| {
 6430                    let project_transaction = apply_code_action.await?;
 6431                    Self::open_project_transaction(
 6432                        &editor,
 6433                        workspace,
 6434                        project_transaction,
 6435                        title,
 6436                        cx,
 6437                    )
 6438                    .await
 6439                }))
 6440            }
 6441            CodeActionsItem::DebugScenario(scenario) => {
 6442                let context = actions_menu.actions.context;
 6443
 6444                workspace.update(cx, |workspace, cx| {
 6445                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6446                    workspace.start_debug_session(
 6447                        scenario,
 6448                        context,
 6449                        Some(buffer),
 6450                        None,
 6451                        window,
 6452                        cx,
 6453                    );
 6454                });
 6455                Some(Task::ready(Ok(())))
 6456            }
 6457        }
 6458    }
 6459
 6460    pub async fn open_project_transaction(
 6461        editor: &WeakEntity<Editor>,
 6462        workspace: WeakEntity<Workspace>,
 6463        transaction: ProjectTransaction,
 6464        title: String,
 6465        cx: &mut AsyncWindowContext,
 6466    ) -> Result<()> {
 6467        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6468        cx.update(|_, cx| {
 6469            entries.sort_unstable_by_key(|(buffer, _)| {
 6470                buffer.read(cx).file().map(|f| f.path().clone())
 6471            });
 6472        })?;
 6473        if entries.is_empty() {
 6474            return Ok(());
 6475        }
 6476
 6477        // If the project transaction's edits are all contained within this editor, then
 6478        // avoid opening a new editor to display them.
 6479
 6480        if let [(buffer, transaction)] = &*entries {
 6481            let excerpt = editor.update(cx, |editor, cx| {
 6482                editor
 6483                    .buffer()
 6484                    .read(cx)
 6485                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6486            })?;
 6487            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6488                && excerpted_buffer == *buffer
 6489            {
 6490                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6491                    let excerpt_range = excerpt_range.to_offset(buffer);
 6492                    buffer
 6493                        .edited_ranges_for_transaction::<usize>(transaction)
 6494                        .all(|range| {
 6495                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6496                        })
 6497                })?;
 6498
 6499                if all_edits_within_excerpt {
 6500                    return Ok(());
 6501                }
 6502            }
 6503        }
 6504
 6505        let mut ranges_to_highlight = Vec::new();
 6506        let excerpt_buffer = cx.new(|cx| {
 6507            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6508            for (buffer_handle, transaction) in &entries {
 6509                let edited_ranges = buffer_handle
 6510                    .read(cx)
 6511                    .edited_ranges_for_transaction::<Point>(transaction)
 6512                    .collect::<Vec<_>>();
 6513                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6514                    PathKey::for_buffer(buffer_handle, cx),
 6515                    buffer_handle.clone(),
 6516                    edited_ranges,
 6517                    multibuffer_context_lines(cx),
 6518                    cx,
 6519                );
 6520
 6521                ranges_to_highlight.extend(ranges);
 6522            }
 6523            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6524            multibuffer
 6525        })?;
 6526
 6527        workspace.update_in(cx, |workspace, window, cx| {
 6528            let project = workspace.project().clone();
 6529            let editor =
 6530                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6531            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6532            editor.update(cx, |editor, cx| {
 6533                editor.highlight_background::<Self>(
 6534                    &ranges_to_highlight,
 6535                    |theme| theme.colors().editor_highlighted_line_background,
 6536                    cx,
 6537                );
 6538            });
 6539        })?;
 6540
 6541        Ok(())
 6542    }
 6543
 6544    pub fn clear_code_action_providers(&mut self) {
 6545        self.code_action_providers.clear();
 6546        self.available_code_actions.take();
 6547    }
 6548
 6549    pub fn add_code_action_provider(
 6550        &mut self,
 6551        provider: Rc<dyn CodeActionProvider>,
 6552        window: &mut Window,
 6553        cx: &mut Context<Self>,
 6554    ) {
 6555        if self
 6556            .code_action_providers
 6557            .iter()
 6558            .any(|existing_provider| existing_provider.id() == provider.id())
 6559        {
 6560            return;
 6561        }
 6562
 6563        self.code_action_providers.push(provider);
 6564        self.refresh_code_actions(window, cx);
 6565    }
 6566
 6567    pub fn remove_code_action_provider(
 6568        &mut self,
 6569        id: Arc<str>,
 6570        window: &mut Window,
 6571        cx: &mut Context<Self>,
 6572    ) {
 6573        self.code_action_providers
 6574            .retain(|provider| provider.id() != id);
 6575        self.refresh_code_actions(window, cx);
 6576    }
 6577
 6578    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6579        !self.code_action_providers.is_empty()
 6580            && EditorSettings::get_global(cx).toolbar.code_actions
 6581    }
 6582
 6583    pub fn has_available_code_actions(&self) -> bool {
 6584        self.available_code_actions
 6585            .as_ref()
 6586            .is_some_and(|(_, actions)| !actions.is_empty())
 6587    }
 6588
 6589    fn render_inline_code_actions(
 6590        &self,
 6591        icon_size: ui::IconSize,
 6592        display_row: DisplayRow,
 6593        is_active: bool,
 6594        cx: &mut Context<Self>,
 6595    ) -> AnyElement {
 6596        let show_tooltip = !self.context_menu_visible();
 6597        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6598            .icon_size(icon_size)
 6599            .shape(ui::IconButtonShape::Square)
 6600            .icon_color(ui::Color::Hidden)
 6601            .toggle_state(is_active)
 6602            .when(show_tooltip, |this| {
 6603                this.tooltip({
 6604                    let focus_handle = self.focus_handle.clone();
 6605                    move |window, cx| {
 6606                        Tooltip::for_action_in(
 6607                            "Toggle Code Actions",
 6608                            &ToggleCodeActions {
 6609                                deployed_from: None,
 6610                                quick_launch: false,
 6611                            },
 6612                            &focus_handle,
 6613                            window,
 6614                            cx,
 6615                        )
 6616                    }
 6617                })
 6618            })
 6619            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6620                window.focus(&editor.focus_handle(cx));
 6621                editor.toggle_code_actions(
 6622                    &crate::actions::ToggleCodeActions {
 6623                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6624                            display_row,
 6625                        )),
 6626                        quick_launch: false,
 6627                    },
 6628                    window,
 6629                    cx,
 6630                );
 6631            }))
 6632            .into_any_element()
 6633    }
 6634
 6635    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6636        &self.context_menu
 6637    }
 6638
 6639    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6640        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6641            cx.background_executor()
 6642                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6643                .await;
 6644
 6645            let (start_buffer, start, _, end, newest_selection) = this
 6646                .update(cx, |this, cx| {
 6647                    let newest_selection = this.selections.newest_anchor().clone();
 6648                    if newest_selection.head().diff_base_anchor.is_some() {
 6649                        return None;
 6650                    }
 6651                    let newest_selection_adjusted = this.selections.newest_adjusted(cx);
 6652                    let buffer = this.buffer.read(cx);
 6653
 6654                    let (start_buffer, start) =
 6655                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6656                    let (end_buffer, end) =
 6657                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6658
 6659                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6660                })?
 6661                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6662                .context(
 6663                    "Expected selection to lie in a single buffer when refreshing code actions",
 6664                )?;
 6665            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6666                let providers = this.code_action_providers.clone();
 6667                let tasks = this
 6668                    .code_action_providers
 6669                    .iter()
 6670                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6671                    .collect::<Vec<_>>();
 6672                (providers, tasks)
 6673            })?;
 6674
 6675            let mut actions = Vec::new();
 6676            for (provider, provider_actions) in
 6677                providers.into_iter().zip(future::join_all(tasks).await)
 6678            {
 6679                if let Some(provider_actions) = provider_actions.log_err() {
 6680                    actions.extend(provider_actions.into_iter().map(|action| {
 6681                        AvailableCodeAction {
 6682                            excerpt_id: newest_selection.start.excerpt_id,
 6683                            action,
 6684                            provider: provider.clone(),
 6685                        }
 6686                    }));
 6687                }
 6688            }
 6689
 6690            this.update(cx, |this, cx| {
 6691                this.available_code_actions = if actions.is_empty() {
 6692                    None
 6693                } else {
 6694                    Some((
 6695                        Location {
 6696                            buffer: start_buffer,
 6697                            range: start..end,
 6698                        },
 6699                        actions.into(),
 6700                    ))
 6701                };
 6702                cx.notify();
 6703            })
 6704        }));
 6705    }
 6706
 6707    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6708        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6709            self.show_git_blame_inline = false;
 6710
 6711            self.show_git_blame_inline_delay_task =
 6712                Some(cx.spawn_in(window, async move |this, cx| {
 6713                    cx.background_executor().timer(delay).await;
 6714
 6715                    this.update(cx, |this, cx| {
 6716                        this.show_git_blame_inline = true;
 6717                        cx.notify();
 6718                    })
 6719                    .log_err();
 6720                }));
 6721        }
 6722    }
 6723
 6724    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6725        let snapshot = self.snapshot(window, cx);
 6726        let cursor = self.selections.newest::<Point>(cx).head();
 6727        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6728        else {
 6729            return;
 6730        };
 6731
 6732        let Some(blame) = self.blame.as_ref() else {
 6733            return;
 6734        };
 6735
 6736        let row_info = RowInfo {
 6737            buffer_id: Some(buffer.remote_id()),
 6738            buffer_row: Some(point.row),
 6739            ..Default::default()
 6740        };
 6741        let Some((buffer, blame_entry)) = blame
 6742            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6743            .flatten()
 6744        else {
 6745            return;
 6746        };
 6747
 6748        let anchor = self.selections.newest_anchor().head();
 6749        let position = self.to_pixel_point(anchor, &snapshot, window);
 6750        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6751            self.show_blame_popover(
 6752                buffer,
 6753                &blame_entry,
 6754                position + last_bounds.origin,
 6755                true,
 6756                cx,
 6757            );
 6758        };
 6759    }
 6760
 6761    fn show_blame_popover(
 6762        &mut self,
 6763        buffer: BufferId,
 6764        blame_entry: &BlameEntry,
 6765        position: gpui::Point<Pixels>,
 6766        ignore_timeout: bool,
 6767        cx: &mut Context<Self>,
 6768    ) {
 6769        if let Some(state) = &mut self.inline_blame_popover {
 6770            state.hide_task.take();
 6771        } else {
 6772            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6773            let blame_entry = blame_entry.clone();
 6774            let show_task = cx.spawn(async move |editor, cx| {
 6775                if !ignore_timeout {
 6776                    cx.background_executor()
 6777                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6778                        .await;
 6779                }
 6780                editor
 6781                    .update(cx, |editor, cx| {
 6782                        editor.inline_blame_popover_show_task.take();
 6783                        let Some(blame) = editor.blame.as_ref() else {
 6784                            return;
 6785                        };
 6786                        let blame = blame.read(cx);
 6787                        let details = blame.details_for_entry(buffer, &blame_entry);
 6788                        let markdown = cx.new(|cx| {
 6789                            Markdown::new(
 6790                                details
 6791                                    .as_ref()
 6792                                    .map(|message| message.message.clone())
 6793                                    .unwrap_or_default(),
 6794                                None,
 6795                                None,
 6796                                cx,
 6797                            )
 6798                        });
 6799                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6800                            position,
 6801                            hide_task: None,
 6802                            popover_bounds: None,
 6803                            popover_state: InlineBlamePopoverState {
 6804                                scroll_handle: ScrollHandle::new(),
 6805                                commit_message: details,
 6806                                markdown,
 6807                            },
 6808                            keyboard_grace: ignore_timeout,
 6809                        });
 6810                        cx.notify();
 6811                    })
 6812                    .ok();
 6813            });
 6814            self.inline_blame_popover_show_task = Some(show_task);
 6815        }
 6816    }
 6817
 6818    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6819        self.inline_blame_popover_show_task.take();
 6820        if let Some(state) = &mut self.inline_blame_popover {
 6821            let hide_task = cx.spawn(async move |editor, cx| {
 6822                cx.background_executor()
 6823                    .timer(std::time::Duration::from_millis(100))
 6824                    .await;
 6825                editor
 6826                    .update(cx, |editor, cx| {
 6827                        editor.inline_blame_popover.take();
 6828                        cx.notify();
 6829                    })
 6830                    .ok();
 6831            });
 6832            state.hide_task = Some(hide_task);
 6833        }
 6834    }
 6835
 6836    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6837        if self.pending_rename.is_some() {
 6838            return None;
 6839        }
 6840
 6841        let provider = self.semantics_provider.clone()?;
 6842        let buffer = self.buffer.read(cx);
 6843        let newest_selection = self.selections.newest_anchor().clone();
 6844        let cursor_position = newest_selection.head();
 6845        let (cursor_buffer, cursor_buffer_position) =
 6846            buffer.text_anchor_for_position(cursor_position, cx)?;
 6847        let (tail_buffer, tail_buffer_position) =
 6848            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6849        if cursor_buffer != tail_buffer {
 6850            return None;
 6851        }
 6852
 6853        let snapshot = cursor_buffer.read(cx).snapshot();
 6854        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6855        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6856        if start_word_range != end_word_range {
 6857            self.document_highlights_task.take();
 6858            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6859            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6860            return None;
 6861        }
 6862
 6863        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6864        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6865            cx.background_executor()
 6866                .timer(Duration::from_millis(debounce))
 6867                .await;
 6868
 6869            let highlights = if let Some(highlights) = cx
 6870                .update(|cx| {
 6871                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6872                })
 6873                .ok()
 6874                .flatten()
 6875            {
 6876                highlights.await.log_err()
 6877            } else {
 6878                None
 6879            };
 6880
 6881            if let Some(highlights) = highlights {
 6882                this.update(cx, |this, cx| {
 6883                    if this.pending_rename.is_some() {
 6884                        return;
 6885                    }
 6886
 6887                    let buffer = this.buffer.read(cx);
 6888                    if buffer
 6889                        .text_anchor_for_position(cursor_position, cx)
 6890                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6891                    {
 6892                        return;
 6893                    }
 6894
 6895                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6896                    let mut write_ranges = Vec::new();
 6897                    let mut read_ranges = Vec::new();
 6898                    for highlight in highlights {
 6899                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6900                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6901                        {
 6902                            let start = highlight
 6903                                .range
 6904                                .start
 6905                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6906                            let end = highlight
 6907                                .range
 6908                                .end
 6909                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6910                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6911                                continue;
 6912                            }
 6913
 6914                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6915                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6916                                write_ranges.push(range);
 6917                            } else {
 6918                                read_ranges.push(range);
 6919                            }
 6920                        }
 6921                    }
 6922
 6923                    this.highlight_background::<DocumentHighlightRead>(
 6924                        &read_ranges,
 6925                        |theme| theme.colors().editor_document_highlight_read_background,
 6926                        cx,
 6927                    );
 6928                    this.highlight_background::<DocumentHighlightWrite>(
 6929                        &write_ranges,
 6930                        |theme| theme.colors().editor_document_highlight_write_background,
 6931                        cx,
 6932                    );
 6933                    cx.notify();
 6934                })
 6935                .log_err();
 6936            }
 6937        }));
 6938        None
 6939    }
 6940
 6941    fn prepare_highlight_query_from_selection(
 6942        &mut self,
 6943        cx: &mut Context<Editor>,
 6944    ) -> Option<(String, Range<Anchor>)> {
 6945        if matches!(self.mode, EditorMode::SingleLine) {
 6946            return None;
 6947        }
 6948        if !EditorSettings::get_global(cx).selection_highlight {
 6949            return None;
 6950        }
 6951        if self.selections.count() != 1 || self.selections.line_mode() {
 6952            return None;
 6953        }
 6954        let selection = self.selections.newest_anchor();
 6955        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6956        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6957            ..selection.end.to_point(&multi_buffer_snapshot);
 6958        // If the selection spans multiple rows OR it is empty
 6959        if selection_point_range.start.row != selection_point_range.end.row
 6960            || selection_point_range.start.column == selection_point_range.end.column
 6961        {
 6962            return None;
 6963        }
 6964
 6965        let query = multi_buffer_snapshot
 6966            .text_for_range(selection.range())
 6967            .collect::<String>();
 6968        if query.trim().is_empty() {
 6969            return None;
 6970        }
 6971        Some((query, selection.range()))
 6972    }
 6973
 6974    fn update_selection_occurrence_highlights(
 6975        &mut self,
 6976        query_text: String,
 6977        query_range: Range<Anchor>,
 6978        multi_buffer_range_to_query: Range<Point>,
 6979        use_debounce: bool,
 6980        window: &mut Window,
 6981        cx: &mut Context<Editor>,
 6982    ) -> Task<()> {
 6983        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6984        cx.spawn_in(window, async move |editor, cx| {
 6985            if use_debounce {
 6986                cx.background_executor()
 6987                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6988                    .await;
 6989            }
 6990            let match_task = cx.background_spawn(async move {
 6991                let buffer_ranges = multi_buffer_snapshot
 6992                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6993                    .into_iter()
 6994                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6995                let mut match_ranges = Vec::new();
 6996                let Ok(regex) = project::search::SearchQuery::text(
 6997                    query_text.clone(),
 6998                    false,
 6999                    false,
 7000                    false,
 7001                    Default::default(),
 7002                    Default::default(),
 7003                    false,
 7004                    None,
 7005                ) else {
 7006                    return Vec::default();
 7007                };
 7008                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7009                    match_ranges.extend(
 7010                        regex
 7011                            .search(buffer_snapshot, Some(search_range.clone()))
 7012                            .await
 7013                            .into_iter()
 7014                            .filter_map(|match_range| {
 7015                                let match_start = buffer_snapshot
 7016                                    .anchor_after(search_range.start + match_range.start);
 7017                                let match_end = buffer_snapshot
 7018                                    .anchor_before(search_range.start + match_range.end);
 7019                                let match_anchor_range = Anchor::range_in_buffer(
 7020                                    excerpt_id,
 7021                                    buffer_snapshot.remote_id(),
 7022                                    match_start..match_end,
 7023                                );
 7024                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7025                            }),
 7026                    );
 7027                }
 7028                match_ranges
 7029            });
 7030            let match_ranges = match_task.await;
 7031            editor
 7032                .update_in(cx, |editor, _, cx| {
 7033                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7034                    if !match_ranges.is_empty() {
 7035                        editor.highlight_background::<SelectedTextHighlight>(
 7036                            &match_ranges,
 7037                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7038                            cx,
 7039                        )
 7040                    }
 7041                })
 7042                .log_err();
 7043        })
 7044    }
 7045
 7046    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7047        struct NewlineFold;
 7048        let type_id = std::any::TypeId::of::<NewlineFold>();
 7049        if !self.mode.is_single_line() {
 7050            return;
 7051        }
 7052        let snapshot = self.snapshot(window, cx);
 7053        if snapshot.buffer_snapshot().max_point().row == 0 {
 7054            return;
 7055        }
 7056        let task = cx.background_spawn(async move {
 7057            let new_newlines = snapshot
 7058                .buffer_chars_at(0)
 7059                .filter_map(|(c, i)| {
 7060                    if c == '\n' {
 7061                        Some(
 7062                            snapshot.buffer_snapshot().anchor_after(i)
 7063                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7064                        )
 7065                    } else {
 7066                        None
 7067                    }
 7068                })
 7069                .collect::<Vec<_>>();
 7070            let existing_newlines = snapshot
 7071                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7072                .filter_map(|fold| {
 7073                    if fold.placeholder.type_tag == Some(type_id) {
 7074                        Some(fold.range.start..fold.range.end)
 7075                    } else {
 7076                        None
 7077                    }
 7078                })
 7079                .collect::<Vec<_>>();
 7080
 7081            (new_newlines, existing_newlines)
 7082        });
 7083        self.folding_newlines = cx.spawn(async move |this, cx| {
 7084            let (new_newlines, existing_newlines) = task.await;
 7085            if new_newlines == existing_newlines {
 7086                return;
 7087            }
 7088            let placeholder = FoldPlaceholder {
 7089                render: Arc::new(move |_, _, cx| {
 7090                    div()
 7091                        .bg(cx.theme().status().hint_background)
 7092                        .border_b_1()
 7093                        .size_full()
 7094                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7095                        .border_color(cx.theme().status().hint)
 7096                        .child("\\n")
 7097                        .into_any()
 7098                }),
 7099                constrain_width: false,
 7100                merge_adjacent: false,
 7101                type_tag: Some(type_id),
 7102            };
 7103            let creases = new_newlines
 7104                .into_iter()
 7105                .map(|range| Crease::simple(range, placeholder.clone()))
 7106                .collect();
 7107            this.update(cx, |this, cx| {
 7108                this.display_map.update(cx, |display_map, cx| {
 7109                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7110                    display_map.fold(creases, cx);
 7111                });
 7112            })
 7113            .ok();
 7114        });
 7115    }
 7116
 7117    fn refresh_selected_text_highlights(
 7118        &mut self,
 7119        on_buffer_edit: bool,
 7120        window: &mut Window,
 7121        cx: &mut Context<Editor>,
 7122    ) {
 7123        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7124        else {
 7125            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7126            self.quick_selection_highlight_task.take();
 7127            self.debounced_selection_highlight_task.take();
 7128            return;
 7129        };
 7130        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7131        let query_offset = query_range.to_offset(&multi_buffer_snapshot);
 7132        if on_buffer_edit
 7133            || self
 7134                .quick_selection_highlight_task
 7135                .as_ref()
 7136                .is_none_or(|(prev_query_offset, _)| prev_query_offset != &query_offset)
 7137        {
 7138            let multi_buffer_visible_start = self
 7139                .scroll_manager
 7140                .anchor()
 7141                .anchor
 7142                .to_point(&multi_buffer_snapshot);
 7143            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7144                multi_buffer_visible_start
 7145                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7146                Bias::Left,
 7147            );
 7148            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7149            self.quick_selection_highlight_task = Some((
 7150                query_offset.clone(),
 7151                self.update_selection_occurrence_highlights(
 7152                    query_text.clone(),
 7153                    query_range.clone(),
 7154                    multi_buffer_visible_range,
 7155                    false,
 7156                    window,
 7157                    cx,
 7158                ),
 7159            ));
 7160        }
 7161        if on_buffer_edit
 7162            || self
 7163                .debounced_selection_highlight_task
 7164                .as_ref()
 7165                .is_none_or(|(prev_query_offset, _)| prev_query_offset != &query_offset)
 7166        {
 7167            let multi_buffer_start = multi_buffer_snapshot
 7168                .anchor_before(0)
 7169                .to_point(&multi_buffer_snapshot);
 7170            let multi_buffer_end = multi_buffer_snapshot
 7171                .anchor_after(multi_buffer_snapshot.len())
 7172                .to_point(&multi_buffer_snapshot);
 7173            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7174            self.debounced_selection_highlight_task = Some((
 7175                query_offset,
 7176                self.update_selection_occurrence_highlights(
 7177                    query_text,
 7178                    query_range,
 7179                    multi_buffer_full_range,
 7180                    true,
 7181                    window,
 7182                    cx,
 7183                ),
 7184            ));
 7185        }
 7186    }
 7187
 7188    pub fn refresh_edit_prediction(
 7189        &mut self,
 7190        debounce: bool,
 7191        user_requested: bool,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) -> Option<()> {
 7195        if DisableAiSettings::get_global(cx).disable_ai {
 7196            return None;
 7197        }
 7198
 7199        let provider = self.edit_prediction_provider()?;
 7200        let cursor = self.selections.newest_anchor().head();
 7201        let (buffer, cursor_buffer_position) =
 7202            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7203
 7204        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7205            self.discard_edit_prediction(false, cx);
 7206            return None;
 7207        }
 7208
 7209        self.update_visible_edit_prediction(window, cx);
 7210
 7211        if !user_requested
 7212            && (!self.should_show_edit_predictions()
 7213                || !self.is_focused(window)
 7214                || buffer.read(cx).is_empty())
 7215        {
 7216            self.discard_edit_prediction(false, cx);
 7217            return None;
 7218        }
 7219
 7220        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7221        Some(())
 7222    }
 7223
 7224    fn show_edit_predictions_in_menu(&self) -> bool {
 7225        match self.edit_prediction_settings {
 7226            EditPredictionSettings::Disabled => false,
 7227            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7228        }
 7229    }
 7230
 7231    pub fn edit_predictions_enabled(&self) -> bool {
 7232        match self.edit_prediction_settings {
 7233            EditPredictionSettings::Disabled => false,
 7234            EditPredictionSettings::Enabled { .. } => true,
 7235        }
 7236    }
 7237
 7238    fn edit_prediction_requires_modifier(&self) -> bool {
 7239        match self.edit_prediction_settings {
 7240            EditPredictionSettings::Disabled => false,
 7241            EditPredictionSettings::Enabled {
 7242                preview_requires_modifier,
 7243                ..
 7244            } => preview_requires_modifier,
 7245        }
 7246    }
 7247
 7248    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7249        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7250            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7251            self.discard_edit_prediction(false, cx);
 7252        } else {
 7253            let selection = self.selections.newest_anchor();
 7254            let cursor = selection.head();
 7255
 7256            if let Some((buffer, cursor_buffer_position)) =
 7257                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7258            {
 7259                self.edit_prediction_settings =
 7260                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7261            }
 7262        }
 7263    }
 7264
 7265    fn edit_prediction_settings_at_position(
 7266        &self,
 7267        buffer: &Entity<Buffer>,
 7268        buffer_position: language::Anchor,
 7269        cx: &App,
 7270    ) -> EditPredictionSettings {
 7271        if !self.mode.is_full()
 7272            || !self.show_edit_predictions_override.unwrap_or(true)
 7273            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7274        {
 7275            return EditPredictionSettings::Disabled;
 7276        }
 7277
 7278        let buffer = buffer.read(cx);
 7279
 7280        let file = buffer.file();
 7281
 7282        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7283            return EditPredictionSettings::Disabled;
 7284        };
 7285
 7286        let by_provider = matches!(
 7287            self.menu_edit_predictions_policy,
 7288            MenuEditPredictionsPolicy::ByProvider
 7289        );
 7290
 7291        let show_in_menu = by_provider
 7292            && self
 7293                .edit_prediction_provider
 7294                .as_ref()
 7295                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7296
 7297        let preview_requires_modifier =
 7298            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7299
 7300        EditPredictionSettings::Enabled {
 7301            show_in_menu,
 7302            preview_requires_modifier,
 7303        }
 7304    }
 7305
 7306    fn should_show_edit_predictions(&self) -> bool {
 7307        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7308    }
 7309
 7310    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7311        matches!(
 7312            self.edit_prediction_preview,
 7313            EditPredictionPreview::Active { .. }
 7314        )
 7315    }
 7316
 7317    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7318        let cursor = self.selections.newest_anchor().head();
 7319        if let Some((buffer, cursor_position)) =
 7320            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7321        {
 7322            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7323        } else {
 7324            false
 7325        }
 7326    }
 7327
 7328    pub fn supports_minimap(&self, cx: &App) -> bool {
 7329        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7330    }
 7331
 7332    fn edit_predictions_enabled_in_buffer(
 7333        &self,
 7334        buffer: &Entity<Buffer>,
 7335        buffer_position: language::Anchor,
 7336        cx: &App,
 7337    ) -> bool {
 7338        maybe!({
 7339            if self.read_only(cx) {
 7340                return Some(false);
 7341            }
 7342            let provider = self.edit_prediction_provider()?;
 7343            if !provider.is_enabled(buffer, buffer_position, cx) {
 7344                return Some(false);
 7345            }
 7346            let buffer = buffer.read(cx);
 7347            let Some(file) = buffer.file() else {
 7348                return Some(true);
 7349            };
 7350            let settings = all_language_settings(Some(file), cx);
 7351            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7352        })
 7353        .unwrap_or(false)
 7354    }
 7355
 7356    fn cycle_edit_prediction(
 7357        &mut self,
 7358        direction: Direction,
 7359        window: &mut Window,
 7360        cx: &mut Context<Self>,
 7361    ) -> Option<()> {
 7362        let provider = self.edit_prediction_provider()?;
 7363        let cursor = self.selections.newest_anchor().head();
 7364        let (buffer, cursor_buffer_position) =
 7365            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7366        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7367            return None;
 7368        }
 7369
 7370        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7371        self.update_visible_edit_prediction(window, cx);
 7372
 7373        Some(())
 7374    }
 7375
 7376    pub fn show_edit_prediction(
 7377        &mut self,
 7378        _: &ShowEditPrediction,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) {
 7382        if !self.has_active_edit_prediction() {
 7383            self.refresh_edit_prediction(false, true, window, cx);
 7384            return;
 7385        }
 7386
 7387        self.update_visible_edit_prediction(window, cx);
 7388    }
 7389
 7390    pub fn display_cursor_names(
 7391        &mut self,
 7392        _: &DisplayCursorNames,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) {
 7396        self.show_cursor_names(window, cx);
 7397    }
 7398
 7399    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7400        self.show_cursor_names = true;
 7401        cx.notify();
 7402        cx.spawn_in(window, async move |this, cx| {
 7403            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7404            this.update(cx, |this, cx| {
 7405                this.show_cursor_names = false;
 7406                cx.notify()
 7407            })
 7408            .ok()
 7409        })
 7410        .detach();
 7411    }
 7412
 7413    pub fn next_edit_prediction(
 7414        &mut self,
 7415        _: &NextEditPrediction,
 7416        window: &mut Window,
 7417        cx: &mut Context<Self>,
 7418    ) {
 7419        if self.has_active_edit_prediction() {
 7420            self.cycle_edit_prediction(Direction::Next, window, cx);
 7421        } else {
 7422            let is_copilot_disabled = self
 7423                .refresh_edit_prediction(false, true, window, cx)
 7424                .is_none();
 7425            if is_copilot_disabled {
 7426                cx.propagate();
 7427            }
 7428        }
 7429    }
 7430
 7431    pub fn previous_edit_prediction(
 7432        &mut self,
 7433        _: &PreviousEditPrediction,
 7434        window: &mut Window,
 7435        cx: &mut Context<Self>,
 7436    ) {
 7437        if self.has_active_edit_prediction() {
 7438            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7439        } else {
 7440            let is_copilot_disabled = self
 7441                .refresh_edit_prediction(false, true, window, cx)
 7442                .is_none();
 7443            if is_copilot_disabled {
 7444                cx.propagate();
 7445            }
 7446        }
 7447    }
 7448
 7449    pub fn accept_edit_prediction(
 7450        &mut self,
 7451        _: &AcceptEditPrediction,
 7452        window: &mut Window,
 7453        cx: &mut Context<Self>,
 7454    ) {
 7455        if self.show_edit_predictions_in_menu() {
 7456            self.hide_context_menu(window, cx);
 7457        }
 7458
 7459        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7460            return;
 7461        };
 7462
 7463        match &active_edit_prediction.completion {
 7464            EditPrediction::MoveWithin { target, .. } => {
 7465                let target = *target;
 7466
 7467                if let Some(position_map) = &self.last_position_map {
 7468                    if position_map
 7469                        .visible_row_range
 7470                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7471                        || !self.edit_prediction_requires_modifier()
 7472                    {
 7473                        self.unfold_ranges(&[target..target], true, false, cx);
 7474                        // Note that this is also done in vim's handler of the Tab action.
 7475                        self.change_selections(
 7476                            SelectionEffects::scroll(Autoscroll::newest()),
 7477                            window,
 7478                            cx,
 7479                            |selections| {
 7480                                selections.select_anchor_ranges([target..target]);
 7481                            },
 7482                        );
 7483                        self.clear_row_highlights::<EditPredictionPreview>();
 7484
 7485                        self.edit_prediction_preview
 7486                            .set_previous_scroll_position(None);
 7487                    } else {
 7488                        self.edit_prediction_preview
 7489                            .set_previous_scroll_position(Some(
 7490                                position_map.snapshot.scroll_anchor,
 7491                            ));
 7492
 7493                        self.highlight_rows::<EditPredictionPreview>(
 7494                            target..target,
 7495                            cx.theme().colors().editor_highlighted_line_background,
 7496                            RowHighlightOptions {
 7497                                autoscroll: true,
 7498                                ..Default::default()
 7499                            },
 7500                            cx,
 7501                        );
 7502                        self.request_autoscroll(Autoscroll::fit(), cx);
 7503                    }
 7504                }
 7505            }
 7506            EditPrediction::MoveOutside { snapshot, target } => {
 7507                if let Some(workspace) = self.workspace() {
 7508                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7509                        .detach_and_log_err(cx);
 7510                }
 7511            }
 7512            EditPrediction::Edit { edits, .. } => {
 7513                self.report_edit_prediction_event(
 7514                    active_edit_prediction.completion_id.clone(),
 7515                    true,
 7516                    cx,
 7517                );
 7518
 7519                if let Some(provider) = self.edit_prediction_provider() {
 7520                    provider.accept(cx);
 7521                }
 7522
 7523                // Store the transaction ID and selections before applying the edit
 7524                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7525
 7526                let snapshot = self.buffer.read(cx).snapshot(cx);
 7527                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7528
 7529                self.buffer.update(cx, |buffer, cx| {
 7530                    buffer.edit(edits.iter().cloned(), None, cx)
 7531                });
 7532
 7533                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7534                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7535                });
 7536
 7537                let selections = self.selections.disjoint_anchors_arc();
 7538                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7539                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7540                    if has_new_transaction {
 7541                        self.selection_history
 7542                            .insert_transaction(transaction_id_now, selections);
 7543                    }
 7544                }
 7545
 7546                self.update_visible_edit_prediction(window, cx);
 7547                if self.active_edit_prediction.is_none() {
 7548                    self.refresh_edit_prediction(true, true, window, cx);
 7549                }
 7550
 7551                cx.notify();
 7552            }
 7553        }
 7554
 7555        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7556    }
 7557
 7558    pub fn accept_partial_edit_prediction(
 7559        &mut self,
 7560        _: &AcceptPartialEditPrediction,
 7561        window: &mut Window,
 7562        cx: &mut Context<Self>,
 7563    ) {
 7564        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7565            return;
 7566        };
 7567        if self.selections.count() != 1 {
 7568            return;
 7569        }
 7570
 7571        match &active_edit_prediction.completion {
 7572            EditPrediction::MoveWithin { target, .. } => {
 7573                let target = *target;
 7574                self.change_selections(
 7575                    SelectionEffects::scroll(Autoscroll::newest()),
 7576                    window,
 7577                    cx,
 7578                    |selections| {
 7579                        selections.select_anchor_ranges([target..target]);
 7580                    },
 7581                );
 7582            }
 7583            EditPrediction::MoveOutside { snapshot, target } => {
 7584                if let Some(workspace) = self.workspace() {
 7585                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7586                        .detach_and_log_err(cx);
 7587                }
 7588            }
 7589            EditPrediction::Edit { edits, .. } => {
 7590                self.report_edit_prediction_event(
 7591                    active_edit_prediction.completion_id.clone(),
 7592                    true,
 7593                    cx,
 7594                );
 7595
 7596                // Find an insertion that starts at the cursor position.
 7597                let snapshot = self.buffer.read(cx).snapshot(cx);
 7598                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7599                let insertion = edits.iter().find_map(|(range, text)| {
 7600                    let range = range.to_offset(&snapshot);
 7601                    if range.is_empty() && range.start == cursor_offset {
 7602                        Some(text)
 7603                    } else {
 7604                        None
 7605                    }
 7606                });
 7607
 7608                if let Some(text) = insertion {
 7609                    let mut partial_completion = text
 7610                        .chars()
 7611                        .by_ref()
 7612                        .take_while(|c| c.is_alphabetic())
 7613                        .collect::<String>();
 7614                    if partial_completion.is_empty() {
 7615                        partial_completion = text
 7616                            .chars()
 7617                            .by_ref()
 7618                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7619                            .collect::<String>();
 7620                    }
 7621
 7622                    cx.emit(EditorEvent::InputHandled {
 7623                        utf16_range_to_replace: None,
 7624                        text: partial_completion.clone().into(),
 7625                    });
 7626
 7627                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7628
 7629                    self.refresh_edit_prediction(true, true, window, cx);
 7630                    cx.notify();
 7631                } else {
 7632                    self.accept_edit_prediction(&Default::default(), window, cx);
 7633                }
 7634            }
 7635        }
 7636    }
 7637
 7638    fn discard_edit_prediction(
 7639        &mut self,
 7640        should_report_edit_prediction_event: bool,
 7641        cx: &mut Context<Self>,
 7642    ) -> bool {
 7643        if should_report_edit_prediction_event {
 7644            let completion_id = self
 7645                .active_edit_prediction
 7646                .as_ref()
 7647                .and_then(|active_completion| active_completion.completion_id.clone());
 7648
 7649            self.report_edit_prediction_event(completion_id, false, cx);
 7650        }
 7651
 7652        if let Some(provider) = self.edit_prediction_provider() {
 7653            provider.discard(cx);
 7654        }
 7655
 7656        self.take_active_edit_prediction(cx)
 7657    }
 7658
 7659    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7660        let Some(provider) = self.edit_prediction_provider() else {
 7661            return;
 7662        };
 7663
 7664        let Some((_, buffer, _)) = self
 7665            .buffer
 7666            .read(cx)
 7667            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7668        else {
 7669            return;
 7670        };
 7671
 7672        let extension = buffer
 7673            .read(cx)
 7674            .file()
 7675            .and_then(|file| Some(file.path().extension()?.to_string()));
 7676
 7677        let event_type = match accepted {
 7678            true => "Edit Prediction Accepted",
 7679            false => "Edit Prediction Discarded",
 7680        };
 7681        telemetry::event!(
 7682            event_type,
 7683            provider = provider.name(),
 7684            prediction_id = id,
 7685            suggestion_accepted = accepted,
 7686            file_extension = extension,
 7687        );
 7688    }
 7689
 7690    fn open_editor_at_anchor(
 7691        snapshot: &language::BufferSnapshot,
 7692        target: language::Anchor,
 7693        workspace: &Entity<Workspace>,
 7694        window: &mut Window,
 7695        cx: &mut App,
 7696    ) -> Task<Result<()>> {
 7697        workspace.update(cx, |workspace, cx| {
 7698            let path = snapshot.file().map(|file| file.full_path(cx));
 7699            let Some(path) =
 7700                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7701            else {
 7702                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7703            };
 7704            let target = text::ToPoint::to_point(&target, snapshot);
 7705            let item = workspace.open_path(path, None, true, window, cx);
 7706            window.spawn(cx, async move |cx| {
 7707                let Some(editor) = item.await?.downcast::<Editor>() else {
 7708                    return Ok(());
 7709                };
 7710                editor
 7711                    .update_in(cx, |editor, window, cx| {
 7712                        editor.go_to_singleton_buffer_point(target, window, cx);
 7713                    })
 7714                    .ok();
 7715                anyhow::Ok(())
 7716            })
 7717        })
 7718    }
 7719
 7720    pub fn has_active_edit_prediction(&self) -> bool {
 7721        self.active_edit_prediction.is_some()
 7722    }
 7723
 7724    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7725        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7726            return false;
 7727        };
 7728
 7729        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7730        self.clear_highlights::<EditPredictionHighlight>(cx);
 7731        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7732        true
 7733    }
 7734
 7735    /// Returns true when we're displaying the edit prediction popover below the cursor
 7736    /// like we are not previewing and the LSP autocomplete menu is visible
 7737    /// or we are in `when_holding_modifier` mode.
 7738    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7739        if self.edit_prediction_preview_is_active()
 7740            || !self.show_edit_predictions_in_menu()
 7741            || !self.edit_predictions_enabled()
 7742        {
 7743            return false;
 7744        }
 7745
 7746        if self.has_visible_completions_menu() {
 7747            return true;
 7748        }
 7749
 7750        has_completion && self.edit_prediction_requires_modifier()
 7751    }
 7752
 7753    fn handle_modifiers_changed(
 7754        &mut self,
 7755        modifiers: Modifiers,
 7756        position_map: &PositionMap,
 7757        window: &mut Window,
 7758        cx: &mut Context<Self>,
 7759    ) {
 7760        if self.show_edit_predictions_in_menu() {
 7761            self.update_edit_prediction_preview(&modifiers, window, cx);
 7762        }
 7763
 7764        self.update_selection_mode(&modifiers, position_map, window, cx);
 7765
 7766        let mouse_position = window.mouse_position();
 7767        if !position_map.text_hitbox.is_hovered(window) {
 7768            return;
 7769        }
 7770
 7771        self.update_hovered_link(
 7772            position_map.point_for_position(mouse_position),
 7773            &position_map.snapshot,
 7774            modifiers,
 7775            window,
 7776            cx,
 7777        )
 7778    }
 7779
 7780    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7781        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7782        if invert {
 7783            match multi_cursor_setting {
 7784                MultiCursorModifier::Alt => modifiers.alt,
 7785                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7786            }
 7787        } else {
 7788            match multi_cursor_setting {
 7789                MultiCursorModifier::Alt => modifiers.secondary(),
 7790                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7791            }
 7792        }
 7793    }
 7794
 7795    fn columnar_selection_mode(
 7796        modifiers: &Modifiers,
 7797        cx: &mut Context<Self>,
 7798    ) -> Option<ColumnarMode> {
 7799        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7800            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7801                Some(ColumnarMode::FromMouse)
 7802            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7803                Some(ColumnarMode::FromSelection)
 7804            } else {
 7805                None
 7806            }
 7807        } else {
 7808            None
 7809        }
 7810    }
 7811
 7812    fn update_selection_mode(
 7813        &mut self,
 7814        modifiers: &Modifiers,
 7815        position_map: &PositionMap,
 7816        window: &mut Window,
 7817        cx: &mut Context<Self>,
 7818    ) {
 7819        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7820            return;
 7821        };
 7822        if self.selections.pending_anchor().is_none() {
 7823            return;
 7824        }
 7825
 7826        let mouse_position = window.mouse_position();
 7827        let point_for_position = position_map.point_for_position(mouse_position);
 7828        let position = point_for_position.previous_valid;
 7829
 7830        self.select(
 7831            SelectPhase::BeginColumnar {
 7832                position,
 7833                reset: false,
 7834                mode,
 7835                goal_column: point_for_position.exact_unclipped.column(),
 7836            },
 7837            window,
 7838            cx,
 7839        );
 7840    }
 7841
 7842    fn update_edit_prediction_preview(
 7843        &mut self,
 7844        modifiers: &Modifiers,
 7845        window: &mut Window,
 7846        cx: &mut Context<Self>,
 7847    ) {
 7848        let mut modifiers_held = false;
 7849        if let Some(accept_keystroke) = self
 7850            .accept_edit_prediction_keybind(false, window, cx)
 7851            .keystroke()
 7852        {
 7853            modifiers_held = modifiers_held
 7854                || (accept_keystroke.modifiers() == modifiers
 7855                    && accept_keystroke.modifiers().modified());
 7856        };
 7857        if let Some(accept_partial_keystroke) = self
 7858            .accept_edit_prediction_keybind(true, window, cx)
 7859            .keystroke()
 7860        {
 7861            modifiers_held = modifiers_held
 7862                || (accept_partial_keystroke.modifiers() == modifiers
 7863                    && accept_partial_keystroke.modifiers().modified());
 7864        }
 7865
 7866        if modifiers_held {
 7867            if matches!(
 7868                self.edit_prediction_preview,
 7869                EditPredictionPreview::Inactive { .. }
 7870            ) {
 7871                self.edit_prediction_preview = EditPredictionPreview::Active {
 7872                    previous_scroll_position: None,
 7873                    since: Instant::now(),
 7874                };
 7875
 7876                self.update_visible_edit_prediction(window, cx);
 7877                cx.notify();
 7878            }
 7879        } else if let EditPredictionPreview::Active {
 7880            previous_scroll_position,
 7881            since,
 7882        } = self.edit_prediction_preview
 7883        {
 7884            if let (Some(previous_scroll_position), Some(position_map)) =
 7885                (previous_scroll_position, self.last_position_map.as_ref())
 7886            {
 7887                self.set_scroll_position(
 7888                    previous_scroll_position
 7889                        .scroll_position(&position_map.snapshot.display_snapshot),
 7890                    window,
 7891                    cx,
 7892                );
 7893            }
 7894
 7895            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7896                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7897            };
 7898            self.clear_row_highlights::<EditPredictionPreview>();
 7899            self.update_visible_edit_prediction(window, cx);
 7900            cx.notify();
 7901        }
 7902    }
 7903
 7904    fn update_visible_edit_prediction(
 7905        &mut self,
 7906        _window: &mut Window,
 7907        cx: &mut Context<Self>,
 7908    ) -> Option<()> {
 7909        if DisableAiSettings::get_global(cx).disable_ai {
 7910            return None;
 7911        }
 7912
 7913        if self.ime_transaction.is_some() {
 7914            self.discard_edit_prediction(false, cx);
 7915            return None;
 7916        }
 7917
 7918        let selection = self.selections.newest_anchor();
 7919        let cursor = selection.head();
 7920        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7921        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7922        let excerpt_id = cursor.excerpt_id;
 7923
 7924        let show_in_menu = self.show_edit_predictions_in_menu();
 7925        let completions_menu_has_precedence = !show_in_menu
 7926            && (self.context_menu.borrow().is_some()
 7927                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7928
 7929        if completions_menu_has_precedence
 7930            || !offset_selection.is_empty()
 7931            || self
 7932                .active_edit_prediction
 7933                .as_ref()
 7934                .is_some_and(|completion| {
 7935                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7936                        return false;
 7937                    };
 7938                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7939                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7940                    !invalidation_range.contains(&offset_selection.head())
 7941                })
 7942        {
 7943            self.discard_edit_prediction(false, cx);
 7944            return None;
 7945        }
 7946
 7947        self.take_active_edit_prediction(cx);
 7948        let Some(provider) = self.edit_prediction_provider() else {
 7949            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7950            return None;
 7951        };
 7952
 7953        let (buffer, cursor_buffer_position) =
 7954            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7955
 7956        self.edit_prediction_settings =
 7957            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7958
 7959        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7960
 7961        if self.edit_prediction_indent_conflict {
 7962            let cursor_point = cursor.to_point(&multibuffer);
 7963
 7964            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7965
 7966            if let Some((_, indent)) = indents.iter().next()
 7967                && indent.len == cursor_point.column
 7968            {
 7969                self.edit_prediction_indent_conflict = false;
 7970            }
 7971        }
 7972
 7973        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7974
 7975        let (completion_id, edits, edit_preview) = match edit_prediction {
 7976            edit_prediction::EditPrediction::Local {
 7977                id,
 7978                edits,
 7979                edit_preview,
 7980            } => (id, edits, edit_preview),
 7981            edit_prediction::EditPrediction::Jump {
 7982                id,
 7983                snapshot,
 7984                target,
 7985            } => {
 7986                self.stale_edit_prediction_in_menu = None;
 7987                self.active_edit_prediction = Some(EditPredictionState {
 7988                    inlay_ids: vec![],
 7989                    completion: EditPrediction::MoveOutside { snapshot, target },
 7990                    completion_id: id,
 7991                    invalidation_range: None,
 7992                });
 7993                cx.notify();
 7994                return Some(());
 7995            }
 7996        };
 7997
 7998        let edits = edits
 7999            .into_iter()
 8000            .flat_map(|(range, new_text)| {
 8001                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 8002                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 8003                Some((start..end, new_text))
 8004            })
 8005            .collect::<Vec<_>>();
 8006        if edits.is_empty() {
 8007            return None;
 8008        }
 8009
 8010        let first_edit_start = edits.first().unwrap().0.start;
 8011        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8012        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8013
 8014        let last_edit_end = edits.last().unwrap().0.end;
 8015        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8016        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8017
 8018        let cursor_row = cursor.to_point(&multibuffer).row;
 8019
 8020        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8021
 8022        let mut inlay_ids = Vec::new();
 8023        let invalidation_row_range;
 8024        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8025            Some(cursor_row..edit_end_row)
 8026        } else if cursor_row > edit_end_row {
 8027            Some(edit_start_row..cursor_row)
 8028        } else {
 8029            None
 8030        };
 8031        let supports_jump = self
 8032            .edit_prediction_provider
 8033            .as_ref()
 8034            .map(|provider| provider.provider.supports_jump_to_edit())
 8035            .unwrap_or(true);
 8036
 8037        let is_move = supports_jump
 8038            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8039        let completion = if is_move {
 8040            invalidation_row_range =
 8041                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8042            let target = first_edit_start;
 8043            EditPrediction::MoveWithin { target, snapshot }
 8044        } else {
 8045            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8046                && !self.edit_predictions_hidden_for_vim_mode;
 8047
 8048            if show_completions_in_buffer {
 8049                if edits
 8050                    .iter()
 8051                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8052                {
 8053                    let mut inlays = Vec::new();
 8054                    for (range, new_text) in &edits {
 8055                        let inlay = Inlay::edit_prediction(
 8056                            post_inc(&mut self.next_inlay_id),
 8057                            range.start,
 8058                            new_text.as_str(),
 8059                        );
 8060                        inlay_ids.push(inlay.id);
 8061                        inlays.push(inlay);
 8062                    }
 8063
 8064                    self.splice_inlays(&[], inlays, cx);
 8065                } else {
 8066                    let background_color = cx.theme().status().deleted_background;
 8067                    self.highlight_text::<EditPredictionHighlight>(
 8068                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8069                        HighlightStyle {
 8070                            background_color: Some(background_color),
 8071                            ..Default::default()
 8072                        },
 8073                        cx,
 8074                    );
 8075                }
 8076            }
 8077
 8078            invalidation_row_range = edit_start_row..edit_end_row;
 8079
 8080            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8081                if provider.show_tab_accept_marker() {
 8082                    EditDisplayMode::TabAccept
 8083                } else {
 8084                    EditDisplayMode::Inline
 8085                }
 8086            } else {
 8087                EditDisplayMode::DiffPopover
 8088            };
 8089
 8090            EditPrediction::Edit {
 8091                edits,
 8092                edit_preview,
 8093                display_mode,
 8094                snapshot,
 8095            }
 8096        };
 8097
 8098        let invalidation_range = multibuffer
 8099            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8100            ..multibuffer.anchor_after(Point::new(
 8101                invalidation_row_range.end,
 8102                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8103            ));
 8104
 8105        self.stale_edit_prediction_in_menu = None;
 8106        self.active_edit_prediction = Some(EditPredictionState {
 8107            inlay_ids,
 8108            completion,
 8109            completion_id,
 8110            invalidation_range: Some(invalidation_range),
 8111        });
 8112
 8113        cx.notify();
 8114
 8115        Some(())
 8116    }
 8117
 8118    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8119        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8120    }
 8121
 8122    fn clear_tasks(&mut self) {
 8123        self.tasks.clear()
 8124    }
 8125
 8126    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8127        if self.tasks.insert(key, value).is_some() {
 8128            // This case should hopefully be rare, but just in case...
 8129            log::error!(
 8130                "multiple different run targets found on a single line, only the last target will be rendered"
 8131            )
 8132        }
 8133    }
 8134
 8135    /// Get all display points of breakpoints that will be rendered within editor
 8136    ///
 8137    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8138    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8139    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8140    fn active_breakpoints(
 8141        &self,
 8142        range: Range<DisplayRow>,
 8143        window: &mut Window,
 8144        cx: &mut Context<Self>,
 8145    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8146        let mut breakpoint_display_points = HashMap::default();
 8147
 8148        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8149            return breakpoint_display_points;
 8150        };
 8151
 8152        let snapshot = self.snapshot(window, cx);
 8153
 8154        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8155        let Some(project) = self.project() else {
 8156            return breakpoint_display_points;
 8157        };
 8158
 8159        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8160            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8161
 8162        for (buffer_snapshot, range, excerpt_id) in
 8163            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8164        {
 8165            let Some(buffer) = project
 8166                .read(cx)
 8167                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8168            else {
 8169                continue;
 8170            };
 8171            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8172                &buffer,
 8173                Some(
 8174                    buffer_snapshot.anchor_before(range.start)
 8175                        ..buffer_snapshot.anchor_after(range.end),
 8176                ),
 8177                buffer_snapshot,
 8178                cx,
 8179            );
 8180            for (breakpoint, state) in breakpoints {
 8181                let multi_buffer_anchor =
 8182                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8183                let position = multi_buffer_anchor
 8184                    .to_point(multi_buffer_snapshot)
 8185                    .to_display_point(&snapshot);
 8186
 8187                breakpoint_display_points.insert(
 8188                    position.row(),
 8189                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8190                );
 8191            }
 8192        }
 8193
 8194        breakpoint_display_points
 8195    }
 8196
 8197    fn breakpoint_context_menu(
 8198        &self,
 8199        anchor: Anchor,
 8200        window: &mut Window,
 8201        cx: &mut Context<Self>,
 8202    ) -> Entity<ui::ContextMenu> {
 8203        let weak_editor = cx.weak_entity();
 8204        let focus_handle = self.focus_handle(cx);
 8205
 8206        let row = self
 8207            .buffer
 8208            .read(cx)
 8209            .snapshot(cx)
 8210            .summary_for_anchor::<Point>(&anchor)
 8211            .row;
 8212
 8213        let breakpoint = self
 8214            .breakpoint_at_row(row, window, cx)
 8215            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8216
 8217        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8218            "Edit Log Breakpoint"
 8219        } else {
 8220            "Set Log Breakpoint"
 8221        };
 8222
 8223        let condition_breakpoint_msg = if breakpoint
 8224            .as_ref()
 8225            .is_some_and(|bp| bp.1.condition.is_some())
 8226        {
 8227            "Edit Condition Breakpoint"
 8228        } else {
 8229            "Set Condition Breakpoint"
 8230        };
 8231
 8232        let hit_condition_breakpoint_msg = if breakpoint
 8233            .as_ref()
 8234            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8235        {
 8236            "Edit Hit Condition Breakpoint"
 8237        } else {
 8238            "Set Hit Condition Breakpoint"
 8239        };
 8240
 8241        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8242            "Unset Breakpoint"
 8243        } else {
 8244            "Set Breakpoint"
 8245        };
 8246
 8247        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8248
 8249        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8250            BreakpointState::Enabled => Some("Disable"),
 8251            BreakpointState::Disabled => Some("Enable"),
 8252        });
 8253
 8254        let (anchor, breakpoint) =
 8255            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8256
 8257        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8258            menu.on_blur_subscription(Subscription::new(|| {}))
 8259                .context(focus_handle)
 8260                .when(run_to_cursor, |this| {
 8261                    let weak_editor = weak_editor.clone();
 8262                    this.entry("Run to cursor", None, move |window, cx| {
 8263                        weak_editor
 8264                            .update(cx, |editor, cx| {
 8265                                editor.change_selections(
 8266                                    SelectionEffects::no_scroll(),
 8267                                    window,
 8268                                    cx,
 8269                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8270                                );
 8271                            })
 8272                            .ok();
 8273
 8274                        window.dispatch_action(Box::new(RunToCursor), cx);
 8275                    })
 8276                    .separator()
 8277                })
 8278                .when_some(toggle_state_msg, |this, msg| {
 8279                    this.entry(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::InvertState,
 8289                                        cx,
 8290                                    );
 8291                                })
 8292                                .log_err();
 8293                        }
 8294                    })
 8295                })
 8296                .entry(set_breakpoint_msg, None, {
 8297                    let weak_editor = weak_editor.clone();
 8298                    let breakpoint = breakpoint.clone();
 8299                    move |_window, cx| {
 8300                        weak_editor
 8301                            .update(cx, |this, cx| {
 8302                                this.edit_breakpoint_at_anchor(
 8303                                    anchor,
 8304                                    breakpoint.as_ref().clone(),
 8305                                    BreakpointEditAction::Toggle,
 8306                                    cx,
 8307                                );
 8308                            })
 8309                            .log_err();
 8310                    }
 8311                })
 8312                .entry(log_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::Log,
 8322                                    window,
 8323                                    cx,
 8324                                );
 8325                            })
 8326                            .log_err();
 8327                    }
 8328                })
 8329                .entry(condition_breakpoint_msg, None, {
 8330                    let breakpoint = breakpoint.clone();
 8331                    let weak_editor = weak_editor.clone();
 8332                    move |window, cx| {
 8333                        weak_editor
 8334                            .update(cx, |this, cx| {
 8335                                this.add_edit_breakpoint_block(
 8336                                    anchor,
 8337                                    breakpoint.as_ref(),
 8338                                    BreakpointPromptEditAction::Condition,
 8339                                    window,
 8340                                    cx,
 8341                                );
 8342                            })
 8343                            .log_err();
 8344                    }
 8345                })
 8346                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8347                    weak_editor
 8348                        .update(cx, |this, cx| {
 8349                            this.add_edit_breakpoint_block(
 8350                                anchor,
 8351                                breakpoint.as_ref(),
 8352                                BreakpointPromptEditAction::HitCondition,
 8353                                window,
 8354                                cx,
 8355                            );
 8356                        })
 8357                        .log_err();
 8358                })
 8359        })
 8360    }
 8361
 8362    fn render_breakpoint(
 8363        &self,
 8364        position: Anchor,
 8365        row: DisplayRow,
 8366        breakpoint: &Breakpoint,
 8367        state: Option<BreakpointSessionState>,
 8368        cx: &mut Context<Self>,
 8369    ) -> IconButton {
 8370        let is_rejected = state.is_some_and(|s| !s.verified);
 8371        // Is it a breakpoint that shows up when hovering over gutter?
 8372        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8373            (false, false),
 8374            |PhantomBreakpointIndicator {
 8375                 is_active,
 8376                 display_row,
 8377                 collides_with_existing_breakpoint,
 8378             }| {
 8379                (
 8380                    is_active && display_row == row,
 8381                    collides_with_existing_breakpoint,
 8382                )
 8383            },
 8384        );
 8385
 8386        let (color, icon) = {
 8387            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8388                (false, false) => ui::IconName::DebugBreakpoint,
 8389                (true, false) => ui::IconName::DebugLogBreakpoint,
 8390                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8391                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8392            };
 8393
 8394            let color = if is_phantom {
 8395                Color::Hint
 8396            } else if is_rejected {
 8397                Color::Disabled
 8398            } else {
 8399                Color::Debugger
 8400            };
 8401
 8402            (color, icon)
 8403        };
 8404
 8405        let breakpoint = Arc::from(breakpoint.clone());
 8406
 8407        let alt_as_text = gpui::Keystroke {
 8408            modifiers: Modifiers::secondary_key(),
 8409            ..Default::default()
 8410        };
 8411        let primary_action_text = if breakpoint.is_disabled() {
 8412            "Enable breakpoint"
 8413        } else if is_phantom && !collides_with_existing {
 8414            "Set breakpoint"
 8415        } else {
 8416            "Unset breakpoint"
 8417        };
 8418        let focus_handle = self.focus_handle.clone();
 8419
 8420        let meta = if is_rejected {
 8421            SharedString::from("No executable code is associated with this line.")
 8422        } else if collides_with_existing && !breakpoint.is_disabled() {
 8423            SharedString::from(format!(
 8424                "{alt_as_text}-click to disable,\nright-click for more options."
 8425            ))
 8426        } else {
 8427            SharedString::from("Right-click for more options.")
 8428        };
 8429        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8430            .icon_size(IconSize::XSmall)
 8431            .size(ui::ButtonSize::None)
 8432            .when(is_rejected, |this| {
 8433                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8434            })
 8435            .icon_color(color)
 8436            .style(ButtonStyle::Transparent)
 8437            .on_click(cx.listener({
 8438                move |editor, event: &ClickEvent, window, cx| {
 8439                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8440                        BreakpointEditAction::InvertState
 8441                    } else {
 8442                        BreakpointEditAction::Toggle
 8443                    };
 8444
 8445                    window.focus(&editor.focus_handle(cx));
 8446                    editor.edit_breakpoint_at_anchor(
 8447                        position,
 8448                        breakpoint.as_ref().clone(),
 8449                        edit_action,
 8450                        cx,
 8451                    );
 8452                }
 8453            }))
 8454            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8455                editor.set_breakpoint_context_menu(
 8456                    row,
 8457                    Some(position),
 8458                    event.position(),
 8459                    window,
 8460                    cx,
 8461                );
 8462            }))
 8463            .tooltip(move |window, cx| {
 8464                Tooltip::with_meta_in(
 8465                    primary_action_text,
 8466                    Some(&ToggleBreakpoint),
 8467                    meta.clone(),
 8468                    &focus_handle,
 8469                    window,
 8470                    cx,
 8471                )
 8472            })
 8473    }
 8474
 8475    fn build_tasks_context(
 8476        project: &Entity<Project>,
 8477        buffer: &Entity<Buffer>,
 8478        buffer_row: u32,
 8479        tasks: &Arc<RunnableTasks>,
 8480        cx: &mut Context<Self>,
 8481    ) -> Task<Option<task::TaskContext>> {
 8482        let position = Point::new(buffer_row, tasks.column);
 8483        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8484        let location = Location {
 8485            buffer: buffer.clone(),
 8486            range: range_start..range_start,
 8487        };
 8488        // Fill in the environmental variables from the tree-sitter captures
 8489        let mut captured_task_variables = TaskVariables::default();
 8490        for (capture_name, value) in tasks.extra_variables.clone() {
 8491            captured_task_variables.insert(
 8492                task::VariableName::Custom(capture_name.into()),
 8493                value.clone(),
 8494            );
 8495        }
 8496        project.update(cx, |project, cx| {
 8497            project.task_store().update(cx, |task_store, cx| {
 8498                task_store.task_context_for_location(captured_task_variables, location, cx)
 8499            })
 8500        })
 8501    }
 8502
 8503    pub fn spawn_nearest_task(
 8504        &mut self,
 8505        action: &SpawnNearestTask,
 8506        window: &mut Window,
 8507        cx: &mut Context<Self>,
 8508    ) {
 8509        let Some((workspace, _)) = self.workspace.clone() else {
 8510            return;
 8511        };
 8512        let Some(project) = self.project.clone() else {
 8513            return;
 8514        };
 8515
 8516        // Try to find a closest, enclosing node using tree-sitter that has a task
 8517        let Some((buffer, buffer_row, tasks)) = self
 8518            .find_enclosing_node_task(cx)
 8519            // Or find the task that's closest in row-distance.
 8520            .or_else(|| self.find_closest_task(cx))
 8521        else {
 8522            return;
 8523        };
 8524
 8525        let reveal_strategy = action.reveal;
 8526        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8527        cx.spawn_in(window, async move |_, cx| {
 8528            let context = task_context.await?;
 8529            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8530
 8531            let resolved = &mut resolved_task.resolved;
 8532            resolved.reveal = reveal_strategy;
 8533
 8534            workspace
 8535                .update_in(cx, |workspace, window, cx| {
 8536                    workspace.schedule_resolved_task(
 8537                        task_source_kind,
 8538                        resolved_task,
 8539                        false,
 8540                        window,
 8541                        cx,
 8542                    );
 8543                })
 8544                .ok()
 8545        })
 8546        .detach();
 8547    }
 8548
 8549    fn find_closest_task(
 8550        &mut self,
 8551        cx: &mut Context<Self>,
 8552    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8553        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8554
 8555        let ((buffer_id, row), tasks) = self
 8556            .tasks
 8557            .iter()
 8558            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8559
 8560        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8561        let tasks = Arc::new(tasks.to_owned());
 8562        Some((buffer, *row, tasks))
 8563    }
 8564
 8565    fn find_enclosing_node_task(
 8566        &mut self,
 8567        cx: &mut Context<Self>,
 8568    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8569        let snapshot = self.buffer.read(cx).snapshot(cx);
 8570        let offset = self.selections.newest::<usize>(cx).head();
 8571        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8572        let buffer_id = excerpt.buffer().remote_id();
 8573
 8574        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8575        let mut cursor = layer.node().walk();
 8576
 8577        while cursor.goto_first_child_for_byte(offset).is_some() {
 8578            if cursor.node().end_byte() == offset {
 8579                cursor.goto_next_sibling();
 8580            }
 8581        }
 8582
 8583        // Ascend to the smallest ancestor that contains the range and has a task.
 8584        loop {
 8585            let node = cursor.node();
 8586            let node_range = node.byte_range();
 8587            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8588
 8589            // Check if this node contains our offset
 8590            if node_range.start <= offset && node_range.end >= offset {
 8591                // If it contains offset, check for task
 8592                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8593                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8594                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8595                }
 8596            }
 8597
 8598            if !cursor.goto_parent() {
 8599                break;
 8600            }
 8601        }
 8602        None
 8603    }
 8604
 8605    fn render_run_indicator(
 8606        &self,
 8607        _style: &EditorStyle,
 8608        is_active: bool,
 8609        row: DisplayRow,
 8610        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8611        cx: &mut Context<Self>,
 8612    ) -> IconButton {
 8613        let color = Color::Muted;
 8614        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8615
 8616        IconButton::new(
 8617            ("run_indicator", row.0 as usize),
 8618            ui::IconName::PlayOutlined,
 8619        )
 8620        .shape(ui::IconButtonShape::Square)
 8621        .icon_size(IconSize::XSmall)
 8622        .icon_color(color)
 8623        .toggle_state(is_active)
 8624        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8625            let quick_launch = match e {
 8626                ClickEvent::Keyboard(_) => true,
 8627                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8628            };
 8629
 8630            window.focus(&editor.focus_handle(cx));
 8631            editor.toggle_code_actions(
 8632                &ToggleCodeActions {
 8633                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8634                    quick_launch,
 8635                },
 8636                window,
 8637                cx,
 8638            );
 8639        }))
 8640        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8641            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8642        }))
 8643    }
 8644
 8645    pub fn context_menu_visible(&self) -> bool {
 8646        !self.edit_prediction_preview_is_active()
 8647            && self
 8648                .context_menu
 8649                .borrow()
 8650                .as_ref()
 8651                .is_some_and(|menu| menu.visible())
 8652    }
 8653
 8654    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8655        self.context_menu
 8656            .borrow()
 8657            .as_ref()
 8658            .map(|menu| menu.origin())
 8659    }
 8660
 8661    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8662        self.context_menu_options = Some(options);
 8663    }
 8664
 8665    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8666    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8667
 8668    fn render_edit_prediction_popover(
 8669        &mut self,
 8670        text_bounds: &Bounds<Pixels>,
 8671        content_origin: gpui::Point<Pixels>,
 8672        right_margin: Pixels,
 8673        editor_snapshot: &EditorSnapshot,
 8674        visible_row_range: Range<DisplayRow>,
 8675        scroll_top: ScrollOffset,
 8676        scroll_bottom: ScrollOffset,
 8677        line_layouts: &[LineWithInvisibles],
 8678        line_height: Pixels,
 8679        scroll_position: gpui::Point<ScrollOffset>,
 8680        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8681        newest_selection_head: Option<DisplayPoint>,
 8682        editor_width: Pixels,
 8683        style: &EditorStyle,
 8684        window: &mut Window,
 8685        cx: &mut App,
 8686    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8687        if self.mode().is_minimap() {
 8688            return None;
 8689        }
 8690        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8691
 8692        if self.edit_prediction_visible_in_cursor_popover(true) {
 8693            return None;
 8694        }
 8695
 8696        match &active_edit_prediction.completion {
 8697            EditPrediction::MoveWithin { target, .. } => {
 8698                let target_display_point = target.to_display_point(editor_snapshot);
 8699
 8700                if self.edit_prediction_requires_modifier() {
 8701                    if !self.edit_prediction_preview_is_active() {
 8702                        return None;
 8703                    }
 8704
 8705                    self.render_edit_prediction_modifier_jump_popover(
 8706                        text_bounds,
 8707                        content_origin,
 8708                        visible_row_range,
 8709                        line_layouts,
 8710                        line_height,
 8711                        scroll_pixel_position,
 8712                        newest_selection_head,
 8713                        target_display_point,
 8714                        window,
 8715                        cx,
 8716                    )
 8717                } else {
 8718                    self.render_edit_prediction_eager_jump_popover(
 8719                        text_bounds,
 8720                        content_origin,
 8721                        editor_snapshot,
 8722                        visible_row_range,
 8723                        scroll_top,
 8724                        scroll_bottom,
 8725                        line_height,
 8726                        scroll_pixel_position,
 8727                        target_display_point,
 8728                        editor_width,
 8729                        window,
 8730                        cx,
 8731                    )
 8732                }
 8733            }
 8734            EditPrediction::Edit {
 8735                display_mode: EditDisplayMode::Inline,
 8736                ..
 8737            } => None,
 8738            EditPrediction::Edit {
 8739                display_mode: EditDisplayMode::TabAccept,
 8740                edits,
 8741                ..
 8742            } => {
 8743                let range = &edits.first()?.0;
 8744                let target_display_point = range.end.to_display_point(editor_snapshot);
 8745
 8746                self.render_edit_prediction_end_of_line_popover(
 8747                    "Accept",
 8748                    editor_snapshot,
 8749                    visible_row_range,
 8750                    target_display_point,
 8751                    line_height,
 8752                    scroll_pixel_position,
 8753                    content_origin,
 8754                    editor_width,
 8755                    window,
 8756                    cx,
 8757                )
 8758            }
 8759            EditPrediction::Edit {
 8760                edits,
 8761                edit_preview,
 8762                display_mode: EditDisplayMode::DiffPopover,
 8763                snapshot,
 8764            } => self.render_edit_prediction_diff_popover(
 8765                text_bounds,
 8766                content_origin,
 8767                right_margin,
 8768                editor_snapshot,
 8769                visible_row_range,
 8770                line_layouts,
 8771                line_height,
 8772                scroll_position,
 8773                scroll_pixel_position,
 8774                newest_selection_head,
 8775                editor_width,
 8776                style,
 8777                edits,
 8778                edit_preview,
 8779                snapshot,
 8780                window,
 8781                cx,
 8782            ),
 8783            EditPrediction::MoveOutside { snapshot, .. } => {
 8784                let file_name = snapshot
 8785                    .file()
 8786                    .map(|file| file.file_name(cx))
 8787                    .unwrap_or("untitled");
 8788                let mut element = self
 8789                    .render_edit_prediction_line_popover(
 8790                        format!("Jump to {file_name}"),
 8791                        Some(IconName::ZedPredict),
 8792                        window,
 8793                        cx,
 8794                    )
 8795                    .into_any();
 8796
 8797                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8798                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8799                let origin_y = text_bounds.size.height - size.height - px(30.);
 8800                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8801                element.prepaint_at(origin, window, cx);
 8802
 8803                Some((element, origin))
 8804            }
 8805        }
 8806    }
 8807
 8808    fn render_edit_prediction_modifier_jump_popover(
 8809        &mut self,
 8810        text_bounds: &Bounds<Pixels>,
 8811        content_origin: gpui::Point<Pixels>,
 8812        visible_row_range: Range<DisplayRow>,
 8813        line_layouts: &[LineWithInvisibles],
 8814        line_height: Pixels,
 8815        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8816        newest_selection_head: Option<DisplayPoint>,
 8817        target_display_point: DisplayPoint,
 8818        window: &mut Window,
 8819        cx: &mut App,
 8820    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8821        let scrolled_content_origin =
 8822            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8823
 8824        const SCROLL_PADDING_Y: Pixels = px(12.);
 8825
 8826        if target_display_point.row() < visible_row_range.start {
 8827            return self.render_edit_prediction_scroll_popover(
 8828                |_| SCROLL_PADDING_Y,
 8829                IconName::ArrowUp,
 8830                visible_row_range,
 8831                line_layouts,
 8832                newest_selection_head,
 8833                scrolled_content_origin,
 8834                window,
 8835                cx,
 8836            );
 8837        } else if target_display_point.row() >= visible_row_range.end {
 8838            return self.render_edit_prediction_scroll_popover(
 8839                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8840                IconName::ArrowDown,
 8841                visible_row_range,
 8842                line_layouts,
 8843                newest_selection_head,
 8844                scrolled_content_origin,
 8845                window,
 8846                cx,
 8847            );
 8848        }
 8849
 8850        const POLE_WIDTH: Pixels = px(2.);
 8851
 8852        let line_layout =
 8853            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8854        let target_column = target_display_point.column() as usize;
 8855
 8856        let target_x = line_layout.x_for_index(target_column);
 8857        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8858            - scroll_pixel_position.y;
 8859
 8860        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8861
 8862        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8863        border_color.l += 0.001;
 8864
 8865        let mut element = v_flex()
 8866            .items_end()
 8867            .when(flag_on_right, |el| el.items_start())
 8868            .child(if flag_on_right {
 8869                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8870                    .rounded_bl(px(0.))
 8871                    .rounded_tl(px(0.))
 8872                    .border_l_2()
 8873                    .border_color(border_color)
 8874            } else {
 8875                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8876                    .rounded_br(px(0.))
 8877                    .rounded_tr(px(0.))
 8878                    .border_r_2()
 8879                    .border_color(border_color)
 8880            })
 8881            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8882            .into_any();
 8883
 8884        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8885
 8886        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8887            - point(
 8888                if flag_on_right {
 8889                    POLE_WIDTH
 8890                } else {
 8891                    size.width - POLE_WIDTH
 8892                },
 8893                size.height - line_height,
 8894            );
 8895
 8896        origin.x = origin.x.max(content_origin.x);
 8897
 8898        element.prepaint_at(origin, window, cx);
 8899
 8900        Some((element, origin))
 8901    }
 8902
 8903    fn render_edit_prediction_scroll_popover(
 8904        &mut self,
 8905        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8906        scroll_icon: IconName,
 8907        visible_row_range: Range<DisplayRow>,
 8908        line_layouts: &[LineWithInvisibles],
 8909        newest_selection_head: Option<DisplayPoint>,
 8910        scrolled_content_origin: gpui::Point<Pixels>,
 8911        window: &mut Window,
 8912        cx: &mut App,
 8913    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8914        let mut element = self
 8915            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8916            .into_any();
 8917
 8918        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8919
 8920        let cursor = newest_selection_head?;
 8921        let cursor_row_layout =
 8922            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8923        let cursor_column = cursor.column() as usize;
 8924
 8925        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8926
 8927        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8928
 8929        element.prepaint_at(origin, window, cx);
 8930        Some((element, origin))
 8931    }
 8932
 8933    fn render_edit_prediction_eager_jump_popover(
 8934        &mut self,
 8935        text_bounds: &Bounds<Pixels>,
 8936        content_origin: gpui::Point<Pixels>,
 8937        editor_snapshot: &EditorSnapshot,
 8938        visible_row_range: Range<DisplayRow>,
 8939        scroll_top: ScrollOffset,
 8940        scroll_bottom: ScrollOffset,
 8941        line_height: Pixels,
 8942        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8943        target_display_point: DisplayPoint,
 8944        editor_width: Pixels,
 8945        window: &mut Window,
 8946        cx: &mut App,
 8947    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8948        if target_display_point.row().as_f64() < scroll_top {
 8949            let mut element = self
 8950                .render_edit_prediction_line_popover(
 8951                    "Jump to Edit",
 8952                    Some(IconName::ArrowUp),
 8953                    window,
 8954                    cx,
 8955                )
 8956                .into_any();
 8957
 8958            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8959            let offset = point(
 8960                (text_bounds.size.width - size.width) / 2.,
 8961                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8962            );
 8963
 8964            let origin = text_bounds.origin + offset;
 8965            element.prepaint_at(origin, window, cx);
 8966            Some((element, origin))
 8967        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8968            let mut element = self
 8969                .render_edit_prediction_line_popover(
 8970                    "Jump to Edit",
 8971                    Some(IconName::ArrowDown),
 8972                    window,
 8973                    cx,
 8974                )
 8975                .into_any();
 8976
 8977            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8978            let offset = point(
 8979                (text_bounds.size.width - size.width) / 2.,
 8980                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8981            );
 8982
 8983            let origin = text_bounds.origin + offset;
 8984            element.prepaint_at(origin, window, cx);
 8985            Some((element, origin))
 8986        } else {
 8987            self.render_edit_prediction_end_of_line_popover(
 8988                "Jump to Edit",
 8989                editor_snapshot,
 8990                visible_row_range,
 8991                target_display_point,
 8992                line_height,
 8993                scroll_pixel_position,
 8994                content_origin,
 8995                editor_width,
 8996                window,
 8997                cx,
 8998            )
 8999        }
 9000    }
 9001
 9002    fn render_edit_prediction_end_of_line_popover(
 9003        self: &mut Editor,
 9004        label: &'static str,
 9005        editor_snapshot: &EditorSnapshot,
 9006        visible_row_range: Range<DisplayRow>,
 9007        target_display_point: DisplayPoint,
 9008        line_height: Pixels,
 9009        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9010        content_origin: gpui::Point<Pixels>,
 9011        editor_width: Pixels,
 9012        window: &mut Window,
 9013        cx: &mut App,
 9014    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9015        let target_line_end = DisplayPoint::new(
 9016            target_display_point.row(),
 9017            editor_snapshot.line_len(target_display_point.row()),
 9018        );
 9019
 9020        let mut element = self
 9021            .render_edit_prediction_line_popover(label, None, window, cx)
 9022            .into_any();
 9023
 9024        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9025
 9026        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9027
 9028        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9029        let mut origin = start_point
 9030            + line_origin
 9031            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9032        origin.x = origin.x.max(content_origin.x);
 9033
 9034        let max_x = content_origin.x + editor_width - size.width;
 9035
 9036        if origin.x > max_x {
 9037            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9038
 9039            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9040                origin.y += offset;
 9041                IconName::ArrowUp
 9042            } else {
 9043                origin.y -= offset;
 9044                IconName::ArrowDown
 9045            };
 9046
 9047            element = self
 9048                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9049                .into_any();
 9050
 9051            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9052
 9053            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9054        }
 9055
 9056        element.prepaint_at(origin, window, cx);
 9057        Some((element, origin))
 9058    }
 9059
 9060    fn render_edit_prediction_diff_popover(
 9061        self: &Editor,
 9062        text_bounds: &Bounds<Pixels>,
 9063        content_origin: gpui::Point<Pixels>,
 9064        right_margin: Pixels,
 9065        editor_snapshot: &EditorSnapshot,
 9066        visible_row_range: Range<DisplayRow>,
 9067        line_layouts: &[LineWithInvisibles],
 9068        line_height: Pixels,
 9069        scroll_position: gpui::Point<ScrollOffset>,
 9070        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9071        newest_selection_head: Option<DisplayPoint>,
 9072        editor_width: Pixels,
 9073        style: &EditorStyle,
 9074        edits: &Vec<(Range<Anchor>, String)>,
 9075        edit_preview: &Option<language::EditPreview>,
 9076        snapshot: &language::BufferSnapshot,
 9077        window: &mut Window,
 9078        cx: &mut App,
 9079    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9080        let edit_start = edits
 9081            .first()
 9082            .unwrap()
 9083            .0
 9084            .start
 9085            .to_display_point(editor_snapshot);
 9086        let edit_end = edits
 9087            .last()
 9088            .unwrap()
 9089            .0
 9090            .end
 9091            .to_display_point(editor_snapshot);
 9092
 9093        let is_visible = visible_row_range.contains(&edit_start.row())
 9094            || visible_row_range.contains(&edit_end.row());
 9095        if !is_visible {
 9096            return None;
 9097        }
 9098
 9099        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9100            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9101        } else {
 9102            // Fallback for providers without edit_preview
 9103            crate::edit_prediction_fallback_text(edits, cx)
 9104        };
 9105
 9106        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9107        let line_count = highlighted_edits.text.lines().count();
 9108
 9109        const BORDER_WIDTH: Pixels = px(1.);
 9110
 9111        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9112        let has_keybind = keybind.is_some();
 9113
 9114        let mut element = h_flex()
 9115            .items_start()
 9116            .child(
 9117                h_flex()
 9118                    .bg(cx.theme().colors().editor_background)
 9119                    .border(BORDER_WIDTH)
 9120                    .shadow_xs()
 9121                    .border_color(cx.theme().colors().border)
 9122                    .rounded_l_lg()
 9123                    .when(line_count > 1, |el| el.rounded_br_lg())
 9124                    .pr_1()
 9125                    .child(styled_text),
 9126            )
 9127            .child(
 9128                h_flex()
 9129                    .h(line_height + BORDER_WIDTH * 2.)
 9130                    .px_1p5()
 9131                    .gap_1()
 9132                    // Workaround: For some reason, there's a gap if we don't do this
 9133                    .ml(-BORDER_WIDTH)
 9134                    .shadow(vec![gpui::BoxShadow {
 9135                        color: gpui::black().opacity(0.05),
 9136                        offset: point(px(1.), px(1.)),
 9137                        blur_radius: px(2.),
 9138                        spread_radius: px(0.),
 9139                    }])
 9140                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9141                    .border(BORDER_WIDTH)
 9142                    .border_color(cx.theme().colors().border)
 9143                    .rounded_r_lg()
 9144                    .id("edit_prediction_diff_popover_keybind")
 9145                    .when(!has_keybind, |el| {
 9146                        let status_colors = cx.theme().status();
 9147
 9148                        el.bg(status_colors.error_background)
 9149                            .border_color(status_colors.error.opacity(0.6))
 9150                            .child(Icon::new(IconName::Info).color(Color::Error))
 9151                            .cursor_default()
 9152                            .hoverable_tooltip(move |_window, cx| {
 9153                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9154                            })
 9155                    })
 9156                    .children(keybind),
 9157            )
 9158            .into_any();
 9159
 9160        let longest_row =
 9161            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9162        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9163            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9164        } else {
 9165            layout_line(
 9166                longest_row,
 9167                editor_snapshot,
 9168                style,
 9169                editor_width,
 9170                |_| false,
 9171                window,
 9172                cx,
 9173            )
 9174            .width
 9175        };
 9176
 9177        let viewport_bounds =
 9178            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9179                right: -right_margin,
 9180                ..Default::default()
 9181            });
 9182
 9183        let x_after_longest = Pixels::from(
 9184            ScrollPixelOffset::from(
 9185                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9186            ) - scroll_pixel_position.x,
 9187        );
 9188
 9189        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9190
 9191        // Fully visible if it can be displayed within the window (allow overlapping other
 9192        // panes). However, this is only allowed if the popover starts within text_bounds.
 9193        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9194            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9195
 9196        let mut origin = if can_position_to_the_right {
 9197            point(
 9198                x_after_longest,
 9199                text_bounds.origin.y
 9200                    + Pixels::from(
 9201                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9202                            - scroll_pixel_position.y,
 9203                    ),
 9204            )
 9205        } else {
 9206            let cursor_row = newest_selection_head.map(|head| head.row());
 9207            let above_edit = edit_start
 9208                .row()
 9209                .0
 9210                .checked_sub(line_count as u32)
 9211                .map(DisplayRow);
 9212            let below_edit = Some(edit_end.row() + 1);
 9213            let above_cursor =
 9214                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9215            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9216
 9217            // Place the edit popover adjacent to the edit if there is a location
 9218            // available that is onscreen and does not obscure the cursor. Otherwise,
 9219            // place it adjacent to the cursor.
 9220            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9221                .into_iter()
 9222                .flatten()
 9223                .find(|&start_row| {
 9224                    let end_row = start_row + line_count as u32;
 9225                    visible_row_range.contains(&start_row)
 9226                        && visible_row_range.contains(&end_row)
 9227                        && cursor_row
 9228                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9229                })?;
 9230
 9231            content_origin
 9232                + point(
 9233                    Pixels::from(-scroll_pixel_position.x),
 9234                    Pixels::from(
 9235                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9236                    ),
 9237                )
 9238        };
 9239
 9240        origin.x -= BORDER_WIDTH;
 9241
 9242        window.defer_draw(element, origin, 1);
 9243
 9244        // Do not return an element, since it will already be drawn due to defer_draw.
 9245        None
 9246    }
 9247
 9248    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9249        px(30.)
 9250    }
 9251
 9252    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9253        if self.read_only(cx) {
 9254            cx.theme().players().read_only()
 9255        } else {
 9256            self.style.as_ref().unwrap().local_player
 9257        }
 9258    }
 9259
 9260    fn render_edit_prediction_accept_keybind(
 9261        &self,
 9262        window: &mut Window,
 9263        cx: &App,
 9264    ) -> Option<AnyElement> {
 9265        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9266        let accept_keystroke = accept_binding.keystroke()?;
 9267
 9268        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9269
 9270        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9271            Color::Accent
 9272        } else {
 9273            Color::Muted
 9274        };
 9275
 9276        h_flex()
 9277            .px_0p5()
 9278            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9279            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9280            .text_size(TextSize::XSmall.rems(cx))
 9281            .child(h_flex().children(ui::render_modifiers(
 9282                accept_keystroke.modifiers(),
 9283                PlatformStyle::platform(),
 9284                Some(modifiers_color),
 9285                Some(IconSize::XSmall.rems().into()),
 9286                true,
 9287            )))
 9288            .when(is_platform_style_mac, |parent| {
 9289                parent.child(accept_keystroke.key().to_string())
 9290            })
 9291            .when(!is_platform_style_mac, |parent| {
 9292                parent.child(
 9293                    Key::new(
 9294                        util::capitalize(accept_keystroke.key()),
 9295                        Some(Color::Default),
 9296                    )
 9297                    .size(Some(IconSize::XSmall.rems().into())),
 9298                )
 9299            })
 9300            .into_any()
 9301            .into()
 9302    }
 9303
 9304    fn render_edit_prediction_line_popover(
 9305        &self,
 9306        label: impl Into<SharedString>,
 9307        icon: Option<IconName>,
 9308        window: &mut Window,
 9309        cx: &App,
 9310    ) -> Stateful<Div> {
 9311        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9312
 9313        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9314        let has_keybind = keybind.is_some();
 9315
 9316        h_flex()
 9317            .id("ep-line-popover")
 9318            .py_0p5()
 9319            .pl_1()
 9320            .pr(padding_right)
 9321            .gap_1()
 9322            .rounded_md()
 9323            .border_1()
 9324            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9325            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9326            .shadow_xs()
 9327            .when(!has_keybind, |el| {
 9328                let status_colors = cx.theme().status();
 9329
 9330                el.bg(status_colors.error_background)
 9331                    .border_color(status_colors.error.opacity(0.6))
 9332                    .pl_2()
 9333                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9334                    .cursor_default()
 9335                    .hoverable_tooltip(move |_window, cx| {
 9336                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9337                    })
 9338            })
 9339            .children(keybind)
 9340            .child(
 9341                Label::new(label)
 9342                    .size(LabelSize::Small)
 9343                    .when(!has_keybind, |el| {
 9344                        el.color(cx.theme().status().error.into()).strikethrough()
 9345                    }),
 9346            )
 9347            .when(!has_keybind, |el| {
 9348                el.child(
 9349                    h_flex().ml_1().child(
 9350                        Icon::new(IconName::Info)
 9351                            .size(IconSize::Small)
 9352                            .color(cx.theme().status().error.into()),
 9353                    ),
 9354                )
 9355            })
 9356            .when_some(icon, |element, icon| {
 9357                element.child(
 9358                    div()
 9359                        .mt(px(1.5))
 9360                        .child(Icon::new(icon).size(IconSize::Small)),
 9361                )
 9362            })
 9363    }
 9364
 9365    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9366        let accent_color = cx.theme().colors().text_accent;
 9367        let editor_bg_color = cx.theme().colors().editor_background;
 9368        editor_bg_color.blend(accent_color.opacity(0.1))
 9369    }
 9370
 9371    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9372        let accent_color = cx.theme().colors().text_accent;
 9373        let editor_bg_color = cx.theme().colors().editor_background;
 9374        editor_bg_color.blend(accent_color.opacity(0.6))
 9375    }
 9376    fn get_prediction_provider_icon_name(
 9377        provider: &Option<RegisteredEditPredictionProvider>,
 9378    ) -> IconName {
 9379        match provider {
 9380            Some(provider) => match provider.provider.name() {
 9381                "copilot" => IconName::Copilot,
 9382                "supermaven" => IconName::Supermaven,
 9383                _ => IconName::ZedPredict,
 9384            },
 9385            None => IconName::ZedPredict,
 9386        }
 9387    }
 9388
 9389    fn render_edit_prediction_cursor_popover(
 9390        &self,
 9391        min_width: Pixels,
 9392        max_width: Pixels,
 9393        cursor_point: Point,
 9394        style: &EditorStyle,
 9395        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9396        _window: &Window,
 9397        cx: &mut Context<Editor>,
 9398    ) -> Option<AnyElement> {
 9399        let provider = self.edit_prediction_provider.as_ref()?;
 9400        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9401
 9402        let is_refreshing = provider.provider.is_refreshing(cx);
 9403
 9404        fn pending_completion_container(icon: IconName) -> Div {
 9405            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9406        }
 9407
 9408        let completion = match &self.active_edit_prediction {
 9409            Some(prediction) => {
 9410                if !self.has_visible_completions_menu() {
 9411                    const RADIUS: Pixels = px(6.);
 9412                    const BORDER_WIDTH: Pixels = px(1.);
 9413
 9414                    return Some(
 9415                        h_flex()
 9416                            .elevation_2(cx)
 9417                            .border(BORDER_WIDTH)
 9418                            .border_color(cx.theme().colors().border)
 9419                            .when(accept_keystroke.is_none(), |el| {
 9420                                el.border_color(cx.theme().status().error)
 9421                            })
 9422                            .rounded(RADIUS)
 9423                            .rounded_tl(px(0.))
 9424                            .overflow_hidden()
 9425                            .child(div().px_1p5().child(match &prediction.completion {
 9426                                EditPrediction::MoveWithin { target, snapshot } => {
 9427                                    use text::ToPoint as _;
 9428                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9429                                    {
 9430                                        Icon::new(IconName::ZedPredictDown)
 9431                                    } else {
 9432                                        Icon::new(IconName::ZedPredictUp)
 9433                                    }
 9434                                }
 9435                                EditPrediction::MoveOutside { .. } => {
 9436                                    // TODO [zeta2] custom icon for external jump?
 9437                                    Icon::new(provider_icon)
 9438                                }
 9439                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9440                            }))
 9441                            .child(
 9442                                h_flex()
 9443                                    .gap_1()
 9444                                    .py_1()
 9445                                    .px_2()
 9446                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9447                                    .border_l_1()
 9448                                    .border_color(cx.theme().colors().border)
 9449                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9450                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9451                                        el.child(
 9452                                            Label::new("Hold")
 9453                                                .size(LabelSize::Small)
 9454                                                .when(accept_keystroke.is_none(), |el| {
 9455                                                    el.strikethrough()
 9456                                                })
 9457                                                .line_height_style(LineHeightStyle::UiLabel),
 9458                                        )
 9459                                    })
 9460                                    .id("edit_prediction_cursor_popover_keybind")
 9461                                    .when(accept_keystroke.is_none(), |el| {
 9462                                        let status_colors = cx.theme().status();
 9463
 9464                                        el.bg(status_colors.error_background)
 9465                                            .border_color(status_colors.error.opacity(0.6))
 9466                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9467                                            .cursor_default()
 9468                                            .hoverable_tooltip(move |_window, cx| {
 9469                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9470                                                    .into()
 9471                                            })
 9472                                    })
 9473                                    .when_some(
 9474                                        accept_keystroke.as_ref(),
 9475                                        |el, accept_keystroke| {
 9476                                            el.child(h_flex().children(ui::render_modifiers(
 9477                                                accept_keystroke.modifiers(),
 9478                                                PlatformStyle::platform(),
 9479                                                Some(Color::Default),
 9480                                                Some(IconSize::XSmall.rems().into()),
 9481                                                false,
 9482                                            )))
 9483                                        },
 9484                                    ),
 9485                            )
 9486                            .into_any(),
 9487                    );
 9488                }
 9489
 9490                self.render_edit_prediction_cursor_popover_preview(
 9491                    prediction,
 9492                    cursor_point,
 9493                    style,
 9494                    cx,
 9495                )?
 9496            }
 9497
 9498            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9499                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9500                    stale_completion,
 9501                    cursor_point,
 9502                    style,
 9503                    cx,
 9504                )?,
 9505
 9506                None => pending_completion_container(provider_icon)
 9507                    .child(Label::new("...").size(LabelSize::Small)),
 9508            },
 9509
 9510            None => pending_completion_container(provider_icon)
 9511                .child(Label::new("...").size(LabelSize::Small)),
 9512        };
 9513
 9514        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9515            completion
 9516                .with_animation(
 9517                    "loading-completion",
 9518                    Animation::new(Duration::from_secs(2))
 9519                        .repeat()
 9520                        .with_easing(pulsating_between(0.4, 0.8)),
 9521                    |label, delta| label.opacity(delta),
 9522                )
 9523                .into_any_element()
 9524        } else {
 9525            completion.into_any_element()
 9526        };
 9527
 9528        let has_completion = self.active_edit_prediction.is_some();
 9529
 9530        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9531        Some(
 9532            h_flex()
 9533                .min_w(min_width)
 9534                .max_w(max_width)
 9535                .flex_1()
 9536                .elevation_2(cx)
 9537                .border_color(cx.theme().colors().border)
 9538                .child(
 9539                    div()
 9540                        .flex_1()
 9541                        .py_1()
 9542                        .px_2()
 9543                        .overflow_hidden()
 9544                        .child(completion),
 9545                )
 9546                .when_some(accept_keystroke, |el, accept_keystroke| {
 9547                    if !accept_keystroke.modifiers().modified() {
 9548                        return el;
 9549                    }
 9550
 9551                    el.child(
 9552                        h_flex()
 9553                            .h_full()
 9554                            .border_l_1()
 9555                            .rounded_r_lg()
 9556                            .border_color(cx.theme().colors().border)
 9557                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9558                            .gap_1()
 9559                            .py_1()
 9560                            .px_2()
 9561                            .child(
 9562                                h_flex()
 9563                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9564                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9565                                    .child(h_flex().children(ui::render_modifiers(
 9566                                        accept_keystroke.modifiers(),
 9567                                        PlatformStyle::platform(),
 9568                                        Some(if !has_completion {
 9569                                            Color::Muted
 9570                                        } else {
 9571                                            Color::Default
 9572                                        }),
 9573                                        None,
 9574                                        false,
 9575                                    ))),
 9576                            )
 9577                            .child(Label::new("Preview").into_any_element())
 9578                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9579                    )
 9580                })
 9581                .into_any(),
 9582        )
 9583    }
 9584
 9585    fn render_edit_prediction_cursor_popover_preview(
 9586        &self,
 9587        completion: &EditPredictionState,
 9588        cursor_point: Point,
 9589        style: &EditorStyle,
 9590        cx: &mut Context<Editor>,
 9591    ) -> Option<Div> {
 9592        use text::ToPoint as _;
 9593
 9594        fn render_relative_row_jump(
 9595            prefix: impl Into<String>,
 9596            current_row: u32,
 9597            target_row: u32,
 9598        ) -> Div {
 9599            let (row_diff, arrow) = if target_row < current_row {
 9600                (current_row - target_row, IconName::ArrowUp)
 9601            } else {
 9602                (target_row - current_row, IconName::ArrowDown)
 9603            };
 9604
 9605            h_flex()
 9606                .child(
 9607                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9608                        .color(Color::Muted)
 9609                        .size(LabelSize::Small),
 9610                )
 9611                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9612        }
 9613
 9614        let supports_jump = self
 9615            .edit_prediction_provider
 9616            .as_ref()
 9617            .map(|provider| provider.provider.supports_jump_to_edit())
 9618            .unwrap_or(true);
 9619
 9620        match &completion.completion {
 9621            EditPrediction::MoveWithin {
 9622                target, snapshot, ..
 9623            } => {
 9624                if !supports_jump {
 9625                    return None;
 9626                }
 9627
 9628                Some(
 9629                    h_flex()
 9630                        .px_2()
 9631                        .gap_2()
 9632                        .flex_1()
 9633                        .child(
 9634                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9635                                Icon::new(IconName::ZedPredictDown)
 9636                            } else {
 9637                                Icon::new(IconName::ZedPredictUp)
 9638                            },
 9639                        )
 9640                        .child(Label::new("Jump to Edit")),
 9641                )
 9642            }
 9643            EditPrediction::MoveOutside { snapshot, .. } => {
 9644                let file_name = snapshot
 9645                    .file()
 9646                    .map(|file| file.file_name(cx))
 9647                    .unwrap_or("untitled");
 9648                Some(
 9649                    h_flex()
 9650                        .px_2()
 9651                        .gap_2()
 9652                        .flex_1()
 9653                        .child(Icon::new(IconName::ZedPredict))
 9654                        .child(Label::new(format!("Jump to {file_name}"))),
 9655                )
 9656            }
 9657            EditPrediction::Edit {
 9658                edits,
 9659                edit_preview,
 9660                snapshot,
 9661                display_mode: _,
 9662            } => {
 9663                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9664
 9665                let (highlighted_edits, has_more_lines) =
 9666                    if let Some(edit_preview) = edit_preview.as_ref() {
 9667                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9668                            .first_line_preview()
 9669                    } else {
 9670                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9671                    };
 9672
 9673                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9674                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9675
 9676                let preview = h_flex()
 9677                    .gap_1()
 9678                    .min_w_16()
 9679                    .child(styled_text)
 9680                    .when(has_more_lines, |parent| parent.child(""));
 9681
 9682                let left = if supports_jump && first_edit_row != cursor_point.row {
 9683                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9684                        .into_any_element()
 9685                } else {
 9686                    let icon_name =
 9687                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9688                    Icon::new(icon_name).into_any_element()
 9689                };
 9690
 9691                Some(
 9692                    h_flex()
 9693                        .h_full()
 9694                        .flex_1()
 9695                        .gap_2()
 9696                        .pr_1()
 9697                        .overflow_x_hidden()
 9698                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9699                        .child(left)
 9700                        .child(preview),
 9701                )
 9702            }
 9703        }
 9704    }
 9705
 9706    pub fn render_context_menu(
 9707        &self,
 9708        style: &EditorStyle,
 9709        max_height_in_lines: u32,
 9710        window: &mut Window,
 9711        cx: &mut Context<Editor>,
 9712    ) -> Option<AnyElement> {
 9713        let menu = self.context_menu.borrow();
 9714        let menu = menu.as_ref()?;
 9715        if !menu.visible() {
 9716            return None;
 9717        };
 9718        Some(menu.render(style, max_height_in_lines, window, cx))
 9719    }
 9720
 9721    fn render_context_menu_aside(
 9722        &mut self,
 9723        max_size: Size<Pixels>,
 9724        window: &mut Window,
 9725        cx: &mut Context<Editor>,
 9726    ) -> Option<AnyElement> {
 9727        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9728            if menu.visible() {
 9729                menu.render_aside(max_size, window, cx)
 9730            } else {
 9731                None
 9732            }
 9733        })
 9734    }
 9735
 9736    fn hide_context_menu(
 9737        &mut self,
 9738        window: &mut Window,
 9739        cx: &mut Context<Self>,
 9740    ) -> Option<CodeContextMenu> {
 9741        cx.notify();
 9742        self.completion_tasks.clear();
 9743        let context_menu = self.context_menu.borrow_mut().take();
 9744        self.stale_edit_prediction_in_menu.take();
 9745        self.update_visible_edit_prediction(window, cx);
 9746        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9747            && let Some(completion_provider) = &self.completion_provider
 9748        {
 9749            completion_provider.selection_changed(None, window, cx);
 9750        }
 9751        context_menu
 9752    }
 9753
 9754    fn show_snippet_choices(
 9755        &mut self,
 9756        choices: &Vec<String>,
 9757        selection: Range<Anchor>,
 9758        cx: &mut Context<Self>,
 9759    ) {
 9760        let Some((_, buffer, _)) = self
 9761            .buffer()
 9762            .read(cx)
 9763            .excerpt_containing(selection.start, cx)
 9764        else {
 9765            return;
 9766        };
 9767        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9768        else {
 9769            return;
 9770        };
 9771        if buffer != end_buffer {
 9772            log::error!("expected anchor range to have matching buffer IDs");
 9773            return;
 9774        }
 9775
 9776        let id = post_inc(&mut self.next_completion_id);
 9777        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9778        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9779            CompletionsMenu::new_snippet_choices(
 9780                id,
 9781                true,
 9782                choices,
 9783                selection,
 9784                buffer,
 9785                snippet_sort_order,
 9786            ),
 9787        ));
 9788    }
 9789
 9790    pub fn insert_snippet(
 9791        &mut self,
 9792        insertion_ranges: &[Range<usize>],
 9793        snippet: Snippet,
 9794        window: &mut Window,
 9795        cx: &mut Context<Self>,
 9796    ) -> Result<()> {
 9797        struct Tabstop<T> {
 9798            is_end_tabstop: bool,
 9799            ranges: Vec<Range<T>>,
 9800            choices: Option<Vec<String>>,
 9801        }
 9802
 9803        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9804            let snippet_text: Arc<str> = snippet.text.clone().into();
 9805            let edits = insertion_ranges
 9806                .iter()
 9807                .cloned()
 9808                .map(|range| (range, snippet_text.clone()));
 9809            let autoindent_mode = AutoindentMode::Block {
 9810                original_indent_columns: Vec::new(),
 9811            };
 9812            buffer.edit(edits, Some(autoindent_mode), cx);
 9813
 9814            let snapshot = &*buffer.read(cx);
 9815            let snippet = &snippet;
 9816            snippet
 9817                .tabstops
 9818                .iter()
 9819                .map(|tabstop| {
 9820                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9821                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9822                    });
 9823                    let mut tabstop_ranges = tabstop
 9824                        .ranges
 9825                        .iter()
 9826                        .flat_map(|tabstop_range| {
 9827                            let mut delta = 0_isize;
 9828                            insertion_ranges.iter().map(move |insertion_range| {
 9829                                let insertion_start = insertion_range.start as isize + delta;
 9830                                delta +=
 9831                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9832
 9833                                let start = ((insertion_start + tabstop_range.start) as usize)
 9834                                    .min(snapshot.len());
 9835                                let end = ((insertion_start + tabstop_range.end) as usize)
 9836                                    .min(snapshot.len());
 9837                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9838                            })
 9839                        })
 9840                        .collect::<Vec<_>>();
 9841                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9842
 9843                    Tabstop {
 9844                        is_end_tabstop,
 9845                        ranges: tabstop_ranges,
 9846                        choices: tabstop.choices.clone(),
 9847                    }
 9848                })
 9849                .collect::<Vec<_>>()
 9850        });
 9851        if let Some(tabstop) = tabstops.first() {
 9852            self.change_selections(Default::default(), window, cx, |s| {
 9853                // Reverse order so that the first range is the newest created selection.
 9854                // Completions will use it and autoscroll will prioritize it.
 9855                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9856            });
 9857
 9858            if let Some(choices) = &tabstop.choices
 9859                && let Some(selection) = tabstop.ranges.first()
 9860            {
 9861                self.show_snippet_choices(choices, selection.clone(), cx)
 9862            }
 9863
 9864            // If we're already at the last tabstop and it's at the end of the snippet,
 9865            // we're done, we don't need to keep the state around.
 9866            if !tabstop.is_end_tabstop {
 9867                let choices = tabstops
 9868                    .iter()
 9869                    .map(|tabstop| tabstop.choices.clone())
 9870                    .collect();
 9871
 9872                let ranges = tabstops
 9873                    .into_iter()
 9874                    .map(|tabstop| tabstop.ranges)
 9875                    .collect::<Vec<_>>();
 9876
 9877                self.snippet_stack.push(SnippetState {
 9878                    active_index: 0,
 9879                    ranges,
 9880                    choices,
 9881                });
 9882            }
 9883
 9884            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9885            if self.autoclose_regions.is_empty() {
 9886                let snapshot = self.buffer.read(cx).snapshot(cx);
 9887                let mut all_selections = self.selections.all::<Point>(cx);
 9888                for selection in &mut all_selections {
 9889                    let selection_head = selection.head();
 9890                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9891                        continue;
 9892                    };
 9893
 9894                    let mut bracket_pair = None;
 9895                    let max_lookup_length = scope
 9896                        .brackets()
 9897                        .map(|(pair, _)| {
 9898                            pair.start
 9899                                .as_str()
 9900                                .chars()
 9901                                .count()
 9902                                .max(pair.end.as_str().chars().count())
 9903                        })
 9904                        .max();
 9905                    if let Some(max_lookup_length) = max_lookup_length {
 9906                        let next_text = snapshot
 9907                            .chars_at(selection_head)
 9908                            .take(max_lookup_length)
 9909                            .collect::<String>();
 9910                        let prev_text = snapshot
 9911                            .reversed_chars_at(selection_head)
 9912                            .take(max_lookup_length)
 9913                            .collect::<String>();
 9914
 9915                        for (pair, enabled) in scope.brackets() {
 9916                            if enabled
 9917                                && pair.close
 9918                                && prev_text.starts_with(pair.start.as_str())
 9919                                && next_text.starts_with(pair.end.as_str())
 9920                            {
 9921                                bracket_pair = Some(pair.clone());
 9922                                break;
 9923                            }
 9924                        }
 9925                    }
 9926
 9927                    if let Some(pair) = bracket_pair {
 9928                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9929                        let autoclose_enabled =
 9930                            self.use_autoclose && snapshot_settings.use_autoclose;
 9931                        if autoclose_enabled {
 9932                            let start = snapshot.anchor_after(selection_head);
 9933                            let end = snapshot.anchor_after(selection_head);
 9934                            self.autoclose_regions.push(AutocloseRegion {
 9935                                selection_id: selection.id,
 9936                                range: start..end,
 9937                                pair,
 9938                            });
 9939                        }
 9940                    }
 9941                }
 9942            }
 9943        }
 9944        Ok(())
 9945    }
 9946
 9947    pub fn move_to_next_snippet_tabstop(
 9948        &mut self,
 9949        window: &mut Window,
 9950        cx: &mut Context<Self>,
 9951    ) -> bool {
 9952        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9953    }
 9954
 9955    pub fn move_to_prev_snippet_tabstop(
 9956        &mut self,
 9957        window: &mut Window,
 9958        cx: &mut Context<Self>,
 9959    ) -> bool {
 9960        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9961    }
 9962
 9963    pub fn move_to_snippet_tabstop(
 9964        &mut self,
 9965        bias: Bias,
 9966        window: &mut Window,
 9967        cx: &mut Context<Self>,
 9968    ) -> bool {
 9969        if let Some(mut snippet) = self.snippet_stack.pop() {
 9970            match bias {
 9971                Bias::Left => {
 9972                    if snippet.active_index > 0 {
 9973                        snippet.active_index -= 1;
 9974                    } else {
 9975                        self.snippet_stack.push(snippet);
 9976                        return false;
 9977                    }
 9978                }
 9979                Bias::Right => {
 9980                    if snippet.active_index + 1 < snippet.ranges.len() {
 9981                        snippet.active_index += 1;
 9982                    } else {
 9983                        self.snippet_stack.push(snippet);
 9984                        return false;
 9985                    }
 9986                }
 9987            }
 9988            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9989                self.change_selections(Default::default(), window, cx, |s| {
 9990                    // Reverse order so that the first range is the newest created selection.
 9991                    // Completions will use it and autoscroll will prioritize it.
 9992                    s.select_ranges(current_ranges.iter().rev().cloned())
 9993                });
 9994
 9995                if let Some(choices) = &snippet.choices[snippet.active_index]
 9996                    && let Some(selection) = current_ranges.first()
 9997                {
 9998                    self.show_snippet_choices(choices, selection.clone(), cx);
 9999                }
10000
10001                // If snippet state is not at the last tabstop, push it back on the stack
10002                if snippet.active_index + 1 < snippet.ranges.len() {
10003                    self.snippet_stack.push(snippet);
10004                }
10005                return true;
10006            }
10007        }
10008
10009        false
10010    }
10011
10012    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10013        self.transact(window, cx, |this, window, cx| {
10014            this.select_all(&SelectAll, window, cx);
10015            this.insert("", window, cx);
10016        });
10017    }
10018
10019    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10020        if self.read_only(cx) {
10021            return;
10022        }
10023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10024        self.transact(window, cx, |this, window, cx| {
10025            this.select_autoclose_pair(window, cx);
10026            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10027            if !this.linked_edit_ranges.is_empty() {
10028                let selections = this.selections.all::<MultiBufferPoint>(cx);
10029                let snapshot = this.buffer.read(cx).snapshot(cx);
10030
10031                for selection in selections.iter() {
10032                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10033                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10034                    if selection_start.buffer_id != selection_end.buffer_id {
10035                        continue;
10036                    }
10037                    if let Some(ranges) =
10038                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10039                    {
10040                        for (buffer, entries) in ranges {
10041                            linked_ranges.entry(buffer).or_default().extend(entries);
10042                        }
10043                    }
10044                }
10045            }
10046
10047            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10048            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10049            for selection in &mut selections {
10050                if selection.is_empty() {
10051                    let old_head = selection.head();
10052                    let mut new_head =
10053                        movement::left(&display_map, old_head.to_display_point(&display_map))
10054                            .to_point(&display_map);
10055                    if let Some((buffer, line_buffer_range)) = display_map
10056                        .buffer_snapshot()
10057                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10058                    {
10059                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10060                        let indent_len = match indent_size.kind {
10061                            IndentKind::Space => {
10062                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10063                            }
10064                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10065                        };
10066                        if old_head.column <= indent_size.len && old_head.column > 0 {
10067                            let indent_len = indent_len.get();
10068                            new_head = cmp::min(
10069                                new_head,
10070                                MultiBufferPoint::new(
10071                                    old_head.row,
10072                                    ((old_head.column - 1) / indent_len) * indent_len,
10073                                ),
10074                            );
10075                        }
10076                    }
10077
10078                    selection.set_head(new_head, SelectionGoal::None);
10079                }
10080            }
10081
10082            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10083            this.insert("", window, cx);
10084            let empty_str: Arc<str> = Arc::from("");
10085            for (buffer, edits) in linked_ranges {
10086                let snapshot = buffer.read(cx).snapshot();
10087                use text::ToPoint as TP;
10088
10089                let edits = edits
10090                    .into_iter()
10091                    .map(|range| {
10092                        let end_point = TP::to_point(&range.end, &snapshot);
10093                        let mut start_point = TP::to_point(&range.start, &snapshot);
10094
10095                        if end_point == start_point {
10096                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10097                                .saturating_sub(1);
10098                            start_point =
10099                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10100                        };
10101
10102                        (start_point..end_point, empty_str.clone())
10103                    })
10104                    .sorted_by_key(|(range, _)| range.start)
10105                    .collect::<Vec<_>>();
10106                buffer.update(cx, |this, cx| {
10107                    this.edit(edits, None, cx);
10108                })
10109            }
10110            this.refresh_edit_prediction(true, false, window, cx);
10111            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10112        });
10113    }
10114
10115    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10116        if self.read_only(cx) {
10117            return;
10118        }
10119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10120        self.transact(window, cx, |this, window, cx| {
10121            this.change_selections(Default::default(), window, cx, |s| {
10122                s.move_with(|map, selection| {
10123                    if selection.is_empty() {
10124                        let cursor = movement::right(map, selection.head());
10125                        selection.end = cursor;
10126                        selection.reversed = true;
10127                        selection.goal = SelectionGoal::None;
10128                    }
10129                })
10130            });
10131            this.insert("", window, cx);
10132            this.refresh_edit_prediction(true, false, window, cx);
10133        });
10134    }
10135
10136    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10137        if self.mode.is_single_line() {
10138            cx.propagate();
10139            return;
10140        }
10141
10142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10143        if self.move_to_prev_snippet_tabstop(window, cx) {
10144            return;
10145        }
10146        self.outdent(&Outdent, window, cx);
10147    }
10148
10149    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10150        if self.mode.is_single_line() {
10151            cx.propagate();
10152            return;
10153        }
10154
10155        if self.move_to_next_snippet_tabstop(window, cx) {
10156            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10157            return;
10158        }
10159        if self.read_only(cx) {
10160            return;
10161        }
10162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10163        let mut selections = self.selections.all_adjusted(cx);
10164        let buffer = self.buffer.read(cx);
10165        let snapshot = buffer.snapshot(cx);
10166        let rows_iter = selections.iter().map(|s| s.head().row);
10167        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10168
10169        let has_some_cursor_in_whitespace = selections
10170            .iter()
10171            .filter(|selection| selection.is_empty())
10172            .any(|selection| {
10173                let cursor = selection.head();
10174                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10175                cursor.column < current_indent.len
10176            });
10177
10178        let mut edits = Vec::new();
10179        let mut prev_edited_row = 0;
10180        let mut row_delta = 0;
10181        for selection in &mut selections {
10182            if selection.start.row != prev_edited_row {
10183                row_delta = 0;
10184            }
10185            prev_edited_row = selection.end.row;
10186
10187            // If the selection is non-empty, then increase the indentation of the selected lines.
10188            if !selection.is_empty() {
10189                row_delta =
10190                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10191                continue;
10192            }
10193
10194            let cursor = selection.head();
10195            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10196            if let Some(suggested_indent) =
10197                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10198            {
10199                // Don't do anything if already at suggested indent
10200                // and there is any other cursor which is not
10201                if has_some_cursor_in_whitespace
10202                    && cursor.column == current_indent.len
10203                    && current_indent.len == suggested_indent.len
10204                {
10205                    continue;
10206                }
10207
10208                // Adjust line and move cursor to suggested indent
10209                // if cursor is not at suggested indent
10210                if cursor.column < suggested_indent.len
10211                    && cursor.column <= current_indent.len
10212                    && current_indent.len <= suggested_indent.len
10213                {
10214                    selection.start = Point::new(cursor.row, suggested_indent.len);
10215                    selection.end = selection.start;
10216                    if row_delta == 0 {
10217                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10218                            cursor.row,
10219                            current_indent,
10220                            suggested_indent,
10221                        ));
10222                        row_delta = suggested_indent.len - current_indent.len;
10223                    }
10224                    continue;
10225                }
10226
10227                // If current indent is more than suggested indent
10228                // only move cursor to current indent and skip indent
10229                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10230                    selection.start = Point::new(cursor.row, current_indent.len);
10231                    selection.end = selection.start;
10232                    continue;
10233                }
10234            }
10235
10236            // Otherwise, insert a hard or soft tab.
10237            let settings = buffer.language_settings_at(cursor, cx);
10238            let tab_size = if settings.hard_tabs {
10239                IndentSize::tab()
10240            } else {
10241                let tab_size = settings.tab_size.get();
10242                let indent_remainder = snapshot
10243                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10244                    .flat_map(str::chars)
10245                    .fold(row_delta % tab_size, |counter: u32, c| {
10246                        if c == '\t' {
10247                            0
10248                        } else {
10249                            (counter + 1) % tab_size
10250                        }
10251                    });
10252
10253                let chars_to_next_tab_stop = tab_size - indent_remainder;
10254                IndentSize::spaces(chars_to_next_tab_stop)
10255            };
10256            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10257            selection.end = selection.start;
10258            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10259            row_delta += tab_size.len;
10260        }
10261
10262        self.transact(window, cx, |this, window, cx| {
10263            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10264            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10265            this.refresh_edit_prediction(true, false, window, cx);
10266        });
10267    }
10268
10269    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10270        if self.read_only(cx) {
10271            return;
10272        }
10273        if self.mode.is_single_line() {
10274            cx.propagate();
10275            return;
10276        }
10277
10278        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10279        let mut selections = self.selections.all::<Point>(cx);
10280        let mut prev_edited_row = 0;
10281        let mut row_delta = 0;
10282        let mut edits = Vec::new();
10283        let buffer = self.buffer.read(cx);
10284        let snapshot = buffer.snapshot(cx);
10285        for selection in &mut selections {
10286            if selection.start.row != prev_edited_row {
10287                row_delta = 0;
10288            }
10289            prev_edited_row = selection.end.row;
10290
10291            row_delta =
10292                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10293        }
10294
10295        self.transact(window, cx, |this, window, cx| {
10296            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10297            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10298        });
10299    }
10300
10301    fn indent_selection(
10302        buffer: &MultiBuffer,
10303        snapshot: &MultiBufferSnapshot,
10304        selection: &mut Selection<Point>,
10305        edits: &mut Vec<(Range<Point>, String)>,
10306        delta_for_start_row: u32,
10307        cx: &App,
10308    ) -> u32 {
10309        let settings = buffer.language_settings_at(selection.start, cx);
10310        let tab_size = settings.tab_size.get();
10311        let indent_kind = if settings.hard_tabs {
10312            IndentKind::Tab
10313        } else {
10314            IndentKind::Space
10315        };
10316        let mut start_row = selection.start.row;
10317        let mut end_row = selection.end.row + 1;
10318
10319        // If a selection ends at the beginning of a line, don't indent
10320        // that last line.
10321        if selection.end.column == 0 && selection.end.row > selection.start.row {
10322            end_row -= 1;
10323        }
10324
10325        // Avoid re-indenting a row that has already been indented by a
10326        // previous selection, but still update this selection's column
10327        // to reflect that indentation.
10328        if delta_for_start_row > 0 {
10329            start_row += 1;
10330            selection.start.column += delta_for_start_row;
10331            if selection.end.row == selection.start.row {
10332                selection.end.column += delta_for_start_row;
10333            }
10334        }
10335
10336        let mut delta_for_end_row = 0;
10337        let has_multiple_rows = start_row + 1 != end_row;
10338        for row in start_row..end_row {
10339            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10340            let indent_delta = match (current_indent.kind, indent_kind) {
10341                (IndentKind::Space, IndentKind::Space) => {
10342                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10343                    IndentSize::spaces(columns_to_next_tab_stop)
10344                }
10345                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10346                (_, IndentKind::Tab) => IndentSize::tab(),
10347            };
10348
10349            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10350                0
10351            } else {
10352                selection.start.column
10353            };
10354            let row_start = Point::new(row, start);
10355            edits.push((
10356                row_start..row_start,
10357                indent_delta.chars().collect::<String>(),
10358            ));
10359
10360            // Update this selection's endpoints to reflect the indentation.
10361            if row == selection.start.row {
10362                selection.start.column += indent_delta.len;
10363            }
10364            if row == selection.end.row {
10365                selection.end.column += indent_delta.len;
10366                delta_for_end_row = indent_delta.len;
10367            }
10368        }
10369
10370        if selection.start.row == selection.end.row {
10371            delta_for_start_row + delta_for_end_row
10372        } else {
10373            delta_for_end_row
10374        }
10375    }
10376
10377    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10378        if self.read_only(cx) {
10379            return;
10380        }
10381        if self.mode.is_single_line() {
10382            cx.propagate();
10383            return;
10384        }
10385
10386        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10387        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10388        let selections = self.selections.all::<Point>(cx);
10389        let mut deletion_ranges = Vec::new();
10390        let mut last_outdent = None;
10391        {
10392            let buffer = self.buffer.read(cx);
10393            let snapshot = buffer.snapshot(cx);
10394            for selection in &selections {
10395                let settings = buffer.language_settings_at(selection.start, cx);
10396                let tab_size = settings.tab_size.get();
10397                let mut rows = selection.spanned_rows(false, &display_map);
10398
10399                // Avoid re-outdenting a row that has already been outdented by a
10400                // previous selection.
10401                if let Some(last_row) = last_outdent
10402                    && last_row == rows.start
10403                {
10404                    rows.start = rows.start.next_row();
10405                }
10406                let has_multiple_rows = rows.len() > 1;
10407                for row in rows.iter_rows() {
10408                    let indent_size = snapshot.indent_size_for_line(row);
10409                    if indent_size.len > 0 {
10410                        let deletion_len = match indent_size.kind {
10411                            IndentKind::Space => {
10412                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10413                                if columns_to_prev_tab_stop == 0 {
10414                                    tab_size
10415                                } else {
10416                                    columns_to_prev_tab_stop
10417                                }
10418                            }
10419                            IndentKind::Tab => 1,
10420                        };
10421                        let start = if has_multiple_rows
10422                            || deletion_len > selection.start.column
10423                            || indent_size.len < selection.start.column
10424                        {
10425                            0
10426                        } else {
10427                            selection.start.column - deletion_len
10428                        };
10429                        deletion_ranges.push(
10430                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10431                        );
10432                        last_outdent = Some(row);
10433                    }
10434                }
10435            }
10436        }
10437
10438        self.transact(window, cx, |this, window, cx| {
10439            this.buffer.update(cx, |buffer, cx| {
10440                let empty_str: Arc<str> = Arc::default();
10441                buffer.edit(
10442                    deletion_ranges
10443                        .into_iter()
10444                        .map(|range| (range, empty_str.clone())),
10445                    None,
10446                    cx,
10447                );
10448            });
10449            let selections = this.selections.all::<usize>(cx);
10450            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10451        });
10452    }
10453
10454    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10455        if self.read_only(cx) {
10456            return;
10457        }
10458        if self.mode.is_single_line() {
10459            cx.propagate();
10460            return;
10461        }
10462
10463        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10464        let selections = self
10465            .selections
10466            .all::<usize>(cx)
10467            .into_iter()
10468            .map(|s| s.range());
10469
10470        self.transact(window, cx, |this, window, cx| {
10471            this.buffer.update(cx, |buffer, cx| {
10472                buffer.autoindent_ranges(selections, cx);
10473            });
10474            let selections = this.selections.all::<usize>(cx);
10475            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10476        });
10477    }
10478
10479    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10480        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10481        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10482        let selections = self.selections.all::<Point>(cx);
10483
10484        let mut new_cursors = Vec::new();
10485        let mut edit_ranges = Vec::new();
10486        let mut selections = selections.iter().peekable();
10487        while let Some(selection) = selections.next() {
10488            let mut rows = selection.spanned_rows(false, &display_map);
10489
10490            // Accumulate contiguous regions of rows that we want to delete.
10491            while let Some(next_selection) = selections.peek() {
10492                let next_rows = next_selection.spanned_rows(false, &display_map);
10493                if next_rows.start <= rows.end {
10494                    rows.end = next_rows.end;
10495                    selections.next().unwrap();
10496                } else {
10497                    break;
10498                }
10499            }
10500
10501            let buffer = display_map.buffer_snapshot();
10502            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10503            let edit_end = if buffer.max_point().row >= rows.end.0 {
10504                // If there's a line after the range, delete the \n from the end of the row range
10505                ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer)
10506            } else {
10507                // If there isn't a line after the range, delete the \n from the line before the
10508                // start of the row range
10509                edit_start = edit_start.saturating_sub(1);
10510                buffer.len()
10511            };
10512
10513            let (cursor, goal) = movement::down_by_rows(
10514                &display_map,
10515                selection.head().to_display_point(&display_map),
10516                rows.len() as u32,
10517                selection.goal,
10518                false,
10519                &self.text_layout_details(window),
10520            );
10521
10522            new_cursors.push((
10523                selection.id,
10524                buffer.anchor_after(cursor.to_point(&display_map)),
10525                goal,
10526            ));
10527            edit_ranges.push(edit_start..edit_end);
10528        }
10529
10530        self.transact(window, cx, |this, window, cx| {
10531            let buffer = this.buffer.update(cx, |buffer, cx| {
10532                let empty_str: Arc<str> = Arc::default();
10533                buffer.edit(
10534                    edit_ranges
10535                        .into_iter()
10536                        .map(|range| (range, empty_str.clone())),
10537                    None,
10538                    cx,
10539                );
10540                buffer.snapshot(cx)
10541            });
10542            let new_selections = new_cursors
10543                .into_iter()
10544                .map(|(id, cursor, goal)| {
10545                    let cursor = cursor.to_point(&buffer);
10546                    Selection {
10547                        id,
10548                        start: cursor,
10549                        end: cursor,
10550                        reversed: false,
10551                        goal,
10552                    }
10553                })
10554                .collect();
10555
10556            this.change_selections(Default::default(), window, cx, |s| {
10557                s.select(new_selections);
10558            });
10559        });
10560    }
10561
10562    pub fn join_lines_impl(
10563        &mut self,
10564        insert_whitespace: bool,
10565        window: &mut Window,
10566        cx: &mut Context<Self>,
10567    ) {
10568        if self.read_only(cx) {
10569            return;
10570        }
10571        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10572        for selection in self.selections.all::<Point>(cx) {
10573            let start = MultiBufferRow(selection.start.row);
10574            // Treat single line selections as if they include the next line. Otherwise this action
10575            // would do nothing for single line selections individual cursors.
10576            let end = if selection.start.row == selection.end.row {
10577                MultiBufferRow(selection.start.row + 1)
10578            } else {
10579                MultiBufferRow(selection.end.row)
10580            };
10581
10582            if let Some(last_row_range) = row_ranges.last_mut()
10583                && start <= last_row_range.end
10584            {
10585                last_row_range.end = end;
10586                continue;
10587            }
10588            row_ranges.push(start..end);
10589        }
10590
10591        let snapshot = self.buffer.read(cx).snapshot(cx);
10592        let mut cursor_positions = Vec::new();
10593        for row_range in &row_ranges {
10594            let anchor = snapshot.anchor_before(Point::new(
10595                row_range.end.previous_row().0,
10596                snapshot.line_len(row_range.end.previous_row()),
10597            ));
10598            cursor_positions.push(anchor..anchor);
10599        }
10600
10601        self.transact(window, cx, |this, window, cx| {
10602            for row_range in row_ranges.into_iter().rev() {
10603                for row in row_range.iter_rows().rev() {
10604                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10605                    let next_line_row = row.next_row();
10606                    let indent = snapshot.indent_size_for_line(next_line_row);
10607                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10608
10609                    let replace =
10610                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10611                            " "
10612                        } else {
10613                            ""
10614                        };
10615
10616                    this.buffer.update(cx, |buffer, cx| {
10617                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10618                    });
10619                }
10620            }
10621
10622            this.change_selections(Default::default(), window, cx, |s| {
10623                s.select_anchor_ranges(cursor_positions)
10624            });
10625        });
10626    }
10627
10628    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10630        self.join_lines_impl(true, window, cx);
10631    }
10632
10633    pub fn sort_lines_case_sensitive(
10634        &mut self,
10635        _: &SortLinesCaseSensitive,
10636        window: &mut Window,
10637        cx: &mut Context<Self>,
10638    ) {
10639        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10640    }
10641
10642    pub fn sort_lines_by_length(
10643        &mut self,
10644        _: &SortLinesByLength,
10645        window: &mut Window,
10646        cx: &mut Context<Self>,
10647    ) {
10648        self.manipulate_immutable_lines(window, cx, |lines| {
10649            lines.sort_by_key(|&line| line.chars().count())
10650        })
10651    }
10652
10653    pub fn sort_lines_case_insensitive(
10654        &mut self,
10655        _: &SortLinesCaseInsensitive,
10656        window: &mut Window,
10657        cx: &mut Context<Self>,
10658    ) {
10659        self.manipulate_immutable_lines(window, cx, |lines| {
10660            lines.sort_by_key(|line| line.to_lowercase())
10661        })
10662    }
10663
10664    pub fn unique_lines_case_insensitive(
10665        &mut self,
10666        _: &UniqueLinesCaseInsensitive,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        self.manipulate_immutable_lines(window, cx, |lines| {
10671            let mut seen = HashSet::default();
10672            lines.retain(|line| seen.insert(line.to_lowercase()));
10673        })
10674    }
10675
10676    pub fn unique_lines_case_sensitive(
10677        &mut self,
10678        _: &UniqueLinesCaseSensitive,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        self.manipulate_immutable_lines(window, cx, |lines| {
10683            let mut seen = HashSet::default();
10684            lines.retain(|line| seen.insert(*line));
10685        })
10686    }
10687
10688    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10689        let snapshot = self.buffer.read(cx).snapshot(cx);
10690        for selection in self.selections.disjoint_anchors_arc().iter() {
10691            if snapshot
10692                .language_at(selection.start)
10693                .and_then(|lang| lang.config().wrap_characters.as_ref())
10694                .is_some()
10695            {
10696                return true;
10697            }
10698        }
10699        false
10700    }
10701
10702    fn wrap_selections_in_tag(
10703        &mut self,
10704        _: &WrapSelectionsInTag,
10705        window: &mut Window,
10706        cx: &mut Context<Self>,
10707    ) {
10708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10709
10710        let snapshot = self.buffer.read(cx).snapshot(cx);
10711
10712        let mut edits = Vec::new();
10713        let mut boundaries = Vec::new();
10714
10715        for selection in self.selections.all::<Point>(cx).iter() {
10716            let Some(wrap_config) = snapshot
10717                .language_at(selection.start)
10718                .and_then(|lang| lang.config().wrap_characters.clone())
10719            else {
10720                continue;
10721            };
10722
10723            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10724            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10725
10726            let start_before = snapshot.anchor_before(selection.start);
10727            let end_after = snapshot.anchor_after(selection.end);
10728
10729            edits.push((start_before..start_before, open_tag));
10730            edits.push((end_after..end_after, close_tag));
10731
10732            boundaries.push((
10733                start_before,
10734                end_after,
10735                wrap_config.start_prefix.len(),
10736                wrap_config.end_suffix.len(),
10737            ));
10738        }
10739
10740        if edits.is_empty() {
10741            return;
10742        }
10743
10744        self.transact(window, cx, |this, window, cx| {
10745            let buffer = this.buffer.update(cx, |buffer, cx| {
10746                buffer.edit(edits, None, cx);
10747                buffer.snapshot(cx)
10748            });
10749
10750            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10751            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10752                boundaries.into_iter()
10753            {
10754                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10755                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10756                new_selections.push(open_offset..open_offset);
10757                new_selections.push(close_offset..close_offset);
10758            }
10759
10760            this.change_selections(Default::default(), window, cx, |s| {
10761                s.select_ranges(new_selections);
10762            });
10763
10764            this.request_autoscroll(Autoscroll::fit(), cx);
10765        });
10766    }
10767
10768    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10769        let Some(project) = self.project.clone() else {
10770            return;
10771        };
10772        self.reload(project, window, cx)
10773            .detach_and_notify_err(window, cx);
10774    }
10775
10776    pub fn restore_file(
10777        &mut self,
10778        _: &::git::RestoreFile,
10779        window: &mut Window,
10780        cx: &mut Context<Self>,
10781    ) {
10782        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10783        let mut buffer_ids = HashSet::default();
10784        let snapshot = self.buffer().read(cx).snapshot(cx);
10785        for selection in self.selections.all::<usize>(cx) {
10786            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10787        }
10788
10789        let buffer = self.buffer().read(cx);
10790        let ranges = buffer_ids
10791            .into_iter()
10792            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10793            .collect::<Vec<_>>();
10794
10795        self.restore_hunks_in_ranges(ranges, window, cx);
10796    }
10797
10798    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10800        let selections = self
10801            .selections
10802            .all(cx)
10803            .into_iter()
10804            .map(|s| s.range())
10805            .collect();
10806        self.restore_hunks_in_ranges(selections, window, cx);
10807    }
10808
10809    pub fn restore_hunks_in_ranges(
10810        &mut self,
10811        ranges: Vec<Range<Point>>,
10812        window: &mut Window,
10813        cx: &mut Context<Editor>,
10814    ) {
10815        let mut revert_changes = HashMap::default();
10816        let chunk_by = self
10817            .snapshot(window, cx)
10818            .hunks_for_ranges(ranges)
10819            .into_iter()
10820            .chunk_by(|hunk| hunk.buffer_id);
10821        for (buffer_id, hunks) in &chunk_by {
10822            let hunks = hunks.collect::<Vec<_>>();
10823            for hunk in &hunks {
10824                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10825            }
10826            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10827        }
10828        drop(chunk_by);
10829        if !revert_changes.is_empty() {
10830            self.transact(window, cx, |editor, window, cx| {
10831                editor.restore(revert_changes, window, cx);
10832            });
10833        }
10834    }
10835
10836    pub fn open_active_item_in_terminal(
10837        &mut self,
10838        _: &OpenInTerminal,
10839        window: &mut Window,
10840        cx: &mut Context<Self>,
10841    ) {
10842        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10843            let project_path = buffer.read(cx).project_path(cx)?;
10844            let project = self.project()?.read(cx);
10845            let entry = project.entry_for_path(&project_path, cx)?;
10846            let parent = match &entry.canonical_path {
10847                Some(canonical_path) => canonical_path.to_path_buf(),
10848                None => project.absolute_path(&project_path, cx)?,
10849            }
10850            .parent()?
10851            .to_path_buf();
10852            Some(parent)
10853        }) {
10854            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10855        }
10856    }
10857
10858    fn set_breakpoint_context_menu(
10859        &mut self,
10860        display_row: DisplayRow,
10861        position: Option<Anchor>,
10862        clicked_point: gpui::Point<Pixels>,
10863        window: &mut Window,
10864        cx: &mut Context<Self>,
10865    ) {
10866        let source = self
10867            .buffer
10868            .read(cx)
10869            .snapshot(cx)
10870            .anchor_before(Point::new(display_row.0, 0u32));
10871
10872        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10873
10874        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10875            self,
10876            source,
10877            clicked_point,
10878            context_menu,
10879            window,
10880            cx,
10881        );
10882    }
10883
10884    fn add_edit_breakpoint_block(
10885        &mut self,
10886        anchor: Anchor,
10887        breakpoint: &Breakpoint,
10888        edit_action: BreakpointPromptEditAction,
10889        window: &mut Window,
10890        cx: &mut Context<Self>,
10891    ) {
10892        let weak_editor = cx.weak_entity();
10893        let bp_prompt = cx.new(|cx| {
10894            BreakpointPromptEditor::new(
10895                weak_editor,
10896                anchor,
10897                breakpoint.clone(),
10898                edit_action,
10899                window,
10900                cx,
10901            )
10902        });
10903
10904        let height = bp_prompt.update(cx, |this, cx| {
10905            this.prompt
10906                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10907        });
10908        let cloned_prompt = bp_prompt.clone();
10909        let blocks = vec![BlockProperties {
10910            style: BlockStyle::Sticky,
10911            placement: BlockPlacement::Above(anchor),
10912            height: Some(height),
10913            render: Arc::new(move |cx| {
10914                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10915                cloned_prompt.clone().into_any_element()
10916            }),
10917            priority: 0,
10918        }];
10919
10920        let focus_handle = bp_prompt.focus_handle(cx);
10921        window.focus(&focus_handle);
10922
10923        let block_ids = self.insert_blocks(blocks, None, cx);
10924        bp_prompt.update(cx, |prompt, _| {
10925            prompt.add_block_ids(block_ids);
10926        });
10927    }
10928
10929    pub(crate) fn breakpoint_at_row(
10930        &self,
10931        row: u32,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) -> Option<(Anchor, Breakpoint)> {
10935        let snapshot = self.snapshot(window, cx);
10936        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10937
10938        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10939    }
10940
10941    pub(crate) fn breakpoint_at_anchor(
10942        &self,
10943        breakpoint_position: Anchor,
10944        snapshot: &EditorSnapshot,
10945        cx: &mut Context<Self>,
10946    ) -> Option<(Anchor, Breakpoint)> {
10947        let buffer = self
10948            .buffer
10949            .read(cx)
10950            .buffer_for_anchor(breakpoint_position, cx)?;
10951
10952        let enclosing_excerpt = breakpoint_position.excerpt_id;
10953        let buffer_snapshot = buffer.read(cx).snapshot();
10954
10955        let row = buffer_snapshot
10956            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10957            .row;
10958
10959        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10960        let anchor_end = snapshot
10961            .buffer_snapshot()
10962            .anchor_after(Point::new(row, line_len));
10963
10964        self.breakpoint_store
10965            .as_ref()?
10966            .read_with(cx, |breakpoint_store, cx| {
10967                breakpoint_store
10968                    .breakpoints(
10969                        &buffer,
10970                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10971                        &buffer_snapshot,
10972                        cx,
10973                    )
10974                    .next()
10975                    .and_then(|(bp, _)| {
10976                        let breakpoint_row = buffer_snapshot
10977                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10978                            .row;
10979
10980                        if breakpoint_row == row {
10981                            snapshot
10982                                .buffer_snapshot()
10983                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10984                                .map(|position| (position, bp.bp.clone()))
10985                        } else {
10986                            None
10987                        }
10988                    })
10989            })
10990    }
10991
10992    pub fn edit_log_breakpoint(
10993        &mut self,
10994        _: &EditLogBreakpoint,
10995        window: &mut Window,
10996        cx: &mut Context<Self>,
10997    ) {
10998        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10999            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11000                message: None,
11001                state: BreakpointState::Enabled,
11002                condition: None,
11003                hit_condition: None,
11004            });
11005
11006            self.add_edit_breakpoint_block(
11007                anchor,
11008                &breakpoint,
11009                BreakpointPromptEditAction::Log,
11010                window,
11011                cx,
11012            );
11013        }
11014    }
11015
11016    fn breakpoints_at_cursors(
11017        &self,
11018        window: &mut Window,
11019        cx: &mut Context<Self>,
11020    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11021        let snapshot = self.snapshot(window, cx);
11022        let cursors = self
11023            .selections
11024            .disjoint_anchors_arc()
11025            .iter()
11026            .map(|selection| {
11027                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11028
11029                let breakpoint_position = self
11030                    .breakpoint_at_row(cursor_position.row, window, cx)
11031                    .map(|bp| bp.0)
11032                    .unwrap_or_else(|| {
11033                        snapshot
11034                            .display_snapshot
11035                            .buffer_snapshot()
11036                            .anchor_after(Point::new(cursor_position.row, 0))
11037                    });
11038
11039                let breakpoint = self
11040                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11041                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11042
11043                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11044            })
11045            // 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.
11046            .collect::<HashMap<Anchor, _>>();
11047
11048        cursors.into_iter().collect()
11049    }
11050
11051    pub fn enable_breakpoint(
11052        &mut self,
11053        _: &crate::actions::EnableBreakpoint,
11054        window: &mut Window,
11055        cx: &mut Context<Self>,
11056    ) {
11057        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11058            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11059                continue;
11060            };
11061            self.edit_breakpoint_at_anchor(
11062                anchor,
11063                breakpoint,
11064                BreakpointEditAction::InvertState,
11065                cx,
11066            );
11067        }
11068    }
11069
11070    pub fn disable_breakpoint(
11071        &mut self,
11072        _: &crate::actions::DisableBreakpoint,
11073        window: &mut Window,
11074        cx: &mut Context<Self>,
11075    ) {
11076        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11077            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11078                continue;
11079            };
11080            self.edit_breakpoint_at_anchor(
11081                anchor,
11082                breakpoint,
11083                BreakpointEditAction::InvertState,
11084                cx,
11085            );
11086        }
11087    }
11088
11089    pub fn toggle_breakpoint(
11090        &mut self,
11091        _: &crate::actions::ToggleBreakpoint,
11092        window: &mut Window,
11093        cx: &mut Context<Self>,
11094    ) {
11095        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11096            if let Some(breakpoint) = breakpoint {
11097                self.edit_breakpoint_at_anchor(
11098                    anchor,
11099                    breakpoint,
11100                    BreakpointEditAction::Toggle,
11101                    cx,
11102                );
11103            } else {
11104                self.edit_breakpoint_at_anchor(
11105                    anchor,
11106                    Breakpoint::new_standard(),
11107                    BreakpointEditAction::Toggle,
11108                    cx,
11109                );
11110            }
11111        }
11112    }
11113
11114    pub fn edit_breakpoint_at_anchor(
11115        &mut self,
11116        breakpoint_position: Anchor,
11117        breakpoint: Breakpoint,
11118        edit_action: BreakpointEditAction,
11119        cx: &mut Context<Self>,
11120    ) {
11121        let Some(breakpoint_store) = &self.breakpoint_store else {
11122            return;
11123        };
11124
11125        let Some(buffer) = self
11126            .buffer
11127            .read(cx)
11128            .buffer_for_anchor(breakpoint_position, cx)
11129        else {
11130            return;
11131        };
11132
11133        breakpoint_store.update(cx, |breakpoint_store, cx| {
11134            breakpoint_store.toggle_breakpoint(
11135                buffer,
11136                BreakpointWithPosition {
11137                    position: breakpoint_position.text_anchor,
11138                    bp: breakpoint,
11139                },
11140                edit_action,
11141                cx,
11142            );
11143        });
11144
11145        cx.notify();
11146    }
11147
11148    #[cfg(any(test, feature = "test-support"))]
11149    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11150        self.breakpoint_store.clone()
11151    }
11152
11153    pub fn prepare_restore_change(
11154        &self,
11155        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11156        hunk: &MultiBufferDiffHunk,
11157        cx: &mut App,
11158    ) -> Option<()> {
11159        if hunk.is_created_file() {
11160            return None;
11161        }
11162        let buffer = self.buffer.read(cx);
11163        let diff = buffer.diff_for(hunk.buffer_id)?;
11164        let buffer = buffer.buffer(hunk.buffer_id)?;
11165        let buffer = buffer.read(cx);
11166        let original_text = diff
11167            .read(cx)
11168            .base_text()
11169            .as_rope()
11170            .slice(hunk.diff_base_byte_range.clone());
11171        let buffer_snapshot = buffer.snapshot();
11172        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11173        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11174            probe
11175                .0
11176                .start
11177                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11178                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11179        }) {
11180            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11181            Some(())
11182        } else {
11183            None
11184        }
11185    }
11186
11187    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11188        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11189    }
11190
11191    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11192        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11193    }
11194
11195    fn manipulate_lines<M>(
11196        &mut self,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199        mut manipulate: M,
11200    ) where
11201        M: FnMut(&str) -> LineManipulationResult,
11202    {
11203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11204
11205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11206        let buffer = self.buffer.read(cx).snapshot(cx);
11207
11208        let mut edits = Vec::new();
11209
11210        let selections = self.selections.all::<Point>(cx);
11211        let mut selections = selections.iter().peekable();
11212        let mut contiguous_row_selections = Vec::new();
11213        let mut new_selections = Vec::new();
11214        let mut added_lines = 0;
11215        let mut removed_lines = 0;
11216
11217        while let Some(selection) = selections.next() {
11218            let (start_row, end_row) = consume_contiguous_rows(
11219                &mut contiguous_row_selections,
11220                selection,
11221                &display_map,
11222                &mut selections,
11223            );
11224
11225            let start_point = Point::new(start_row.0, 0);
11226            let end_point = Point::new(
11227                end_row.previous_row().0,
11228                buffer.line_len(end_row.previous_row()),
11229            );
11230            let text = buffer
11231                .text_for_range(start_point..end_point)
11232                .collect::<String>();
11233
11234            let LineManipulationResult {
11235                new_text,
11236                line_count_before,
11237                line_count_after,
11238            } = manipulate(&text);
11239
11240            edits.push((start_point..end_point, new_text));
11241
11242            // Selections must change based on added and removed line count
11243            let start_row =
11244                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11245            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11246            new_selections.push(Selection {
11247                id: selection.id,
11248                start: start_row,
11249                end: end_row,
11250                goal: SelectionGoal::None,
11251                reversed: selection.reversed,
11252            });
11253
11254            if line_count_after > line_count_before {
11255                added_lines += line_count_after - line_count_before;
11256            } else if line_count_before > line_count_after {
11257                removed_lines += line_count_before - line_count_after;
11258            }
11259        }
11260
11261        self.transact(window, cx, |this, window, cx| {
11262            let buffer = this.buffer.update(cx, |buffer, cx| {
11263                buffer.edit(edits, None, cx);
11264                buffer.snapshot(cx)
11265            });
11266
11267            // Recalculate offsets on newly edited buffer
11268            let new_selections = new_selections
11269                .iter()
11270                .map(|s| {
11271                    let start_point = Point::new(s.start.0, 0);
11272                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11273                    Selection {
11274                        id: s.id,
11275                        start: buffer.point_to_offset(start_point),
11276                        end: buffer.point_to_offset(end_point),
11277                        goal: s.goal,
11278                        reversed: s.reversed,
11279                    }
11280                })
11281                .collect();
11282
11283            this.change_selections(Default::default(), window, cx, |s| {
11284                s.select(new_selections);
11285            });
11286
11287            this.request_autoscroll(Autoscroll::fit(), cx);
11288        });
11289    }
11290
11291    fn manipulate_immutable_lines<Fn>(
11292        &mut self,
11293        window: &mut Window,
11294        cx: &mut Context<Self>,
11295        mut callback: Fn,
11296    ) where
11297        Fn: FnMut(&mut Vec<&str>),
11298    {
11299        self.manipulate_lines(window, cx, |text| {
11300            let mut lines: Vec<&str> = text.split('\n').collect();
11301            let line_count_before = lines.len();
11302
11303            callback(&mut lines);
11304
11305            LineManipulationResult {
11306                new_text: lines.join("\n"),
11307                line_count_before,
11308                line_count_after: lines.len(),
11309            }
11310        });
11311    }
11312
11313    fn manipulate_mutable_lines<Fn>(
11314        &mut self,
11315        window: &mut Window,
11316        cx: &mut Context<Self>,
11317        mut callback: Fn,
11318    ) where
11319        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11320    {
11321        self.manipulate_lines(window, cx, |text| {
11322            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11323            let line_count_before = lines.len();
11324
11325            callback(&mut lines);
11326
11327            LineManipulationResult {
11328                new_text: lines.join("\n"),
11329                line_count_before,
11330                line_count_after: lines.len(),
11331            }
11332        });
11333    }
11334
11335    pub fn convert_indentation_to_spaces(
11336        &mut self,
11337        _: &ConvertIndentationToSpaces,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        let settings = self.buffer.read(cx).language_settings(cx);
11342        let tab_size = settings.tab_size.get() as usize;
11343
11344        self.manipulate_mutable_lines(window, cx, |lines| {
11345            // Allocates a reasonably sized scratch buffer once for the whole loop
11346            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11347            // Avoids recomputing spaces that could be inserted many times
11348            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11349                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11350                .collect();
11351
11352            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11353                let mut chars = line.as_ref().chars();
11354                let mut col = 0;
11355                let mut changed = false;
11356
11357                for ch in chars.by_ref() {
11358                    match ch {
11359                        ' ' => {
11360                            reindented_line.push(' ');
11361                            col += 1;
11362                        }
11363                        '\t' => {
11364                            // \t are converted to spaces depending on the current column
11365                            let spaces_len = tab_size - (col % tab_size);
11366                            reindented_line.extend(&space_cache[spaces_len - 1]);
11367                            col += spaces_len;
11368                            changed = true;
11369                        }
11370                        _ => {
11371                            // If we dont append before break, the character is consumed
11372                            reindented_line.push(ch);
11373                            break;
11374                        }
11375                    }
11376                }
11377
11378                if !changed {
11379                    reindented_line.clear();
11380                    continue;
11381                }
11382                // Append the rest of the line and replace old reference with new one
11383                reindented_line.extend(chars);
11384                *line = Cow::Owned(reindented_line.clone());
11385                reindented_line.clear();
11386            }
11387        });
11388    }
11389
11390    pub fn convert_indentation_to_tabs(
11391        &mut self,
11392        _: &ConvertIndentationToTabs,
11393        window: &mut Window,
11394        cx: &mut Context<Self>,
11395    ) {
11396        let settings = self.buffer.read(cx).language_settings(cx);
11397        let tab_size = settings.tab_size.get() as usize;
11398
11399        self.manipulate_mutable_lines(window, cx, |lines| {
11400            // Allocates a reasonably sized buffer once for the whole loop
11401            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11402            // Avoids recomputing spaces that could be inserted many times
11403            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11404                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11405                .collect();
11406
11407            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11408                let mut chars = line.chars();
11409                let mut spaces_count = 0;
11410                let mut first_non_indent_char = None;
11411                let mut changed = false;
11412
11413                for ch in chars.by_ref() {
11414                    match ch {
11415                        ' ' => {
11416                            // Keep track of spaces. Append \t when we reach tab_size
11417                            spaces_count += 1;
11418                            changed = true;
11419                            if spaces_count == tab_size {
11420                                reindented_line.push('\t');
11421                                spaces_count = 0;
11422                            }
11423                        }
11424                        '\t' => {
11425                            reindented_line.push('\t');
11426                            spaces_count = 0;
11427                        }
11428                        _ => {
11429                            // Dont append it yet, we might have remaining spaces
11430                            first_non_indent_char = Some(ch);
11431                            break;
11432                        }
11433                    }
11434                }
11435
11436                if !changed {
11437                    reindented_line.clear();
11438                    continue;
11439                }
11440                // Remaining spaces that didn't make a full tab stop
11441                if spaces_count > 0 {
11442                    reindented_line.extend(&space_cache[spaces_count - 1]);
11443                }
11444                // If we consume an extra character that was not indentation, add it back
11445                if let Some(extra_char) = first_non_indent_char {
11446                    reindented_line.push(extra_char);
11447                }
11448                // Append the rest of the line and replace old reference with new one
11449                reindented_line.extend(chars);
11450                *line = Cow::Owned(reindented_line.clone());
11451                reindented_line.clear();
11452            }
11453        });
11454    }
11455
11456    pub fn convert_to_upper_case(
11457        &mut self,
11458        _: &ConvertToUpperCase,
11459        window: &mut Window,
11460        cx: &mut Context<Self>,
11461    ) {
11462        self.manipulate_text(window, cx, |text| text.to_uppercase())
11463    }
11464
11465    pub fn convert_to_lower_case(
11466        &mut self,
11467        _: &ConvertToLowerCase,
11468        window: &mut Window,
11469        cx: &mut Context<Self>,
11470    ) {
11471        self.manipulate_text(window, cx, |text| text.to_lowercase())
11472    }
11473
11474    pub fn convert_to_title_case(
11475        &mut self,
11476        _: &ConvertToTitleCase,
11477        window: &mut Window,
11478        cx: &mut Context<Self>,
11479    ) {
11480        self.manipulate_text(window, cx, |text| {
11481            text.split('\n')
11482                .map(|line| line.to_case(Case::Title))
11483                .join("\n")
11484        })
11485    }
11486
11487    pub fn convert_to_snake_case(
11488        &mut self,
11489        _: &ConvertToSnakeCase,
11490        window: &mut Window,
11491        cx: &mut Context<Self>,
11492    ) {
11493        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11494    }
11495
11496    pub fn convert_to_kebab_case(
11497        &mut self,
11498        _: &ConvertToKebabCase,
11499        window: &mut Window,
11500        cx: &mut Context<Self>,
11501    ) {
11502        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11503    }
11504
11505    pub fn convert_to_upper_camel_case(
11506        &mut self,
11507        _: &ConvertToUpperCamelCase,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.manipulate_text(window, cx, |text| {
11512            text.split('\n')
11513                .map(|line| line.to_case(Case::UpperCamel))
11514                .join("\n")
11515        })
11516    }
11517
11518    pub fn convert_to_lower_camel_case(
11519        &mut self,
11520        _: &ConvertToLowerCamelCase,
11521        window: &mut Window,
11522        cx: &mut Context<Self>,
11523    ) {
11524        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11525    }
11526
11527    pub fn convert_to_opposite_case(
11528        &mut self,
11529        _: &ConvertToOppositeCase,
11530        window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        self.manipulate_text(window, cx, |text| {
11534            text.chars()
11535                .fold(String::with_capacity(text.len()), |mut t, c| {
11536                    if c.is_uppercase() {
11537                        t.extend(c.to_lowercase());
11538                    } else {
11539                        t.extend(c.to_uppercase());
11540                    }
11541                    t
11542                })
11543        })
11544    }
11545
11546    pub fn convert_to_sentence_case(
11547        &mut self,
11548        _: &ConvertToSentenceCase,
11549        window: &mut Window,
11550        cx: &mut Context<Self>,
11551    ) {
11552        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11553    }
11554
11555    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11556        self.manipulate_text(window, cx, |text| {
11557            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11558            if has_upper_case_characters {
11559                text.to_lowercase()
11560            } else {
11561                text.to_uppercase()
11562            }
11563        })
11564    }
11565
11566    pub fn convert_to_rot13(
11567        &mut self,
11568        _: &ConvertToRot13,
11569        window: &mut Window,
11570        cx: &mut Context<Self>,
11571    ) {
11572        self.manipulate_text(window, cx, |text| {
11573            text.chars()
11574                .map(|c| match c {
11575                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11576                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11577                    _ => c,
11578                })
11579                .collect()
11580        })
11581    }
11582
11583    pub fn convert_to_rot47(
11584        &mut self,
11585        _: &ConvertToRot47,
11586        window: &mut Window,
11587        cx: &mut Context<Self>,
11588    ) {
11589        self.manipulate_text(window, cx, |text| {
11590            text.chars()
11591                .map(|c| {
11592                    let code_point = c as u32;
11593                    if code_point >= 33 && code_point <= 126 {
11594                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11595                    }
11596                    c
11597                })
11598                .collect()
11599        })
11600    }
11601
11602    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11603    where
11604        Fn: FnMut(&str) -> String,
11605    {
11606        let buffer = self.buffer.read(cx).snapshot(cx);
11607
11608        let mut new_selections = Vec::new();
11609        let mut edits = Vec::new();
11610        let mut selection_adjustment = 0i32;
11611
11612        for selection in self.selections.all_adjusted(cx) {
11613            let selection_is_empty = selection.is_empty();
11614
11615            let (start, end) = if selection_is_empty {
11616                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11617                (word_range.start, word_range.end)
11618            } else {
11619                (
11620                    buffer.point_to_offset(selection.start),
11621                    buffer.point_to_offset(selection.end),
11622                )
11623            };
11624
11625            let text = buffer.text_for_range(start..end).collect::<String>();
11626            let old_length = text.len() as i32;
11627            let text = callback(&text);
11628
11629            new_selections.push(Selection {
11630                start: (start as i32 - selection_adjustment) as usize,
11631                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11632                goal: SelectionGoal::None,
11633                id: selection.id,
11634                reversed: selection.reversed,
11635            });
11636
11637            selection_adjustment += old_length - text.len() as i32;
11638
11639            edits.push((start..end, text));
11640        }
11641
11642        self.transact(window, cx, |this, window, cx| {
11643            this.buffer.update(cx, |buffer, cx| {
11644                buffer.edit(edits, None, cx);
11645            });
11646
11647            this.change_selections(Default::default(), window, cx, |s| {
11648                s.select(new_selections);
11649            });
11650
11651            this.request_autoscroll(Autoscroll::fit(), cx);
11652        });
11653    }
11654
11655    pub fn move_selection_on_drop(
11656        &mut self,
11657        selection: &Selection<Anchor>,
11658        target: DisplayPoint,
11659        is_cut: bool,
11660        window: &mut Window,
11661        cx: &mut Context<Self>,
11662    ) {
11663        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11664        let buffer = display_map.buffer_snapshot();
11665        let mut edits = Vec::new();
11666        let insert_point = display_map
11667            .clip_point(target, Bias::Left)
11668            .to_point(&display_map);
11669        let text = buffer
11670            .text_for_range(selection.start..selection.end)
11671            .collect::<String>();
11672        if is_cut {
11673            edits.push(((selection.start..selection.end), String::new()));
11674        }
11675        let insert_anchor = buffer.anchor_before(insert_point);
11676        edits.push(((insert_anchor..insert_anchor), text));
11677        let last_edit_start = insert_anchor.bias_left(buffer);
11678        let last_edit_end = insert_anchor.bias_right(buffer);
11679        self.transact(window, cx, |this, window, cx| {
11680            this.buffer.update(cx, |buffer, cx| {
11681                buffer.edit(edits, None, cx);
11682            });
11683            this.change_selections(Default::default(), window, cx, |s| {
11684                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11685            });
11686        });
11687    }
11688
11689    pub fn clear_selection_drag_state(&mut self) {
11690        self.selection_drag_state = SelectionDragState::None;
11691    }
11692
11693    pub fn duplicate(
11694        &mut self,
11695        upwards: bool,
11696        whole_lines: bool,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11701
11702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11703        let buffer = display_map.buffer_snapshot();
11704        let selections = self.selections.all::<Point>(cx);
11705
11706        let mut edits = Vec::new();
11707        let mut selections_iter = selections.iter().peekable();
11708        while let Some(selection) = selections_iter.next() {
11709            let mut rows = selection.spanned_rows(false, &display_map);
11710            // duplicate line-wise
11711            if whole_lines || selection.start == selection.end {
11712                // Avoid duplicating the same lines twice.
11713                while let Some(next_selection) = selections_iter.peek() {
11714                    let next_rows = next_selection.spanned_rows(false, &display_map);
11715                    if next_rows.start < rows.end {
11716                        rows.end = next_rows.end;
11717                        selections_iter.next().unwrap();
11718                    } else {
11719                        break;
11720                    }
11721                }
11722
11723                // Copy the text from the selected row region and splice it either at the start
11724                // or end of the region.
11725                let start = Point::new(rows.start.0, 0);
11726                let end = Point::new(
11727                    rows.end.previous_row().0,
11728                    buffer.line_len(rows.end.previous_row()),
11729                );
11730
11731                let mut text = buffer.text_for_range(start..end).collect::<String>();
11732
11733                let insert_location = if upwards {
11734                    // When duplicating upward, we need to insert before the current line.
11735                    // If we're on the last line and it doesn't end with a newline,
11736                    // we need to add a newline before the duplicated content.
11737                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11738                        && buffer.max_point().column > 0
11739                        && !text.ends_with('\n');
11740
11741                    if needs_leading_newline {
11742                        text.insert(0, '\n');
11743                        end
11744                    } else {
11745                        text.push('\n');
11746                        Point::new(rows.end.0, 0)
11747                    }
11748                } else {
11749                    text.push('\n');
11750                    start
11751                };
11752                edits.push((insert_location..insert_location, text));
11753            } else {
11754                // duplicate character-wise
11755                let start = selection.start;
11756                let end = selection.end;
11757                let text = buffer.text_for_range(start..end).collect::<String>();
11758                edits.push((selection.end..selection.end, text));
11759            }
11760        }
11761
11762        self.transact(window, cx, |this, _, cx| {
11763            this.buffer.update(cx, |buffer, cx| {
11764                buffer.edit(edits, None, cx);
11765            });
11766
11767            this.request_autoscroll(Autoscroll::fit(), cx);
11768        });
11769    }
11770
11771    pub fn duplicate_line_up(
11772        &mut self,
11773        _: &DuplicateLineUp,
11774        window: &mut Window,
11775        cx: &mut Context<Self>,
11776    ) {
11777        self.duplicate(true, true, window, cx);
11778    }
11779
11780    pub fn duplicate_line_down(
11781        &mut self,
11782        _: &DuplicateLineDown,
11783        window: &mut Window,
11784        cx: &mut Context<Self>,
11785    ) {
11786        self.duplicate(false, true, window, cx);
11787    }
11788
11789    pub fn duplicate_selection(
11790        &mut self,
11791        _: &DuplicateSelection,
11792        window: &mut Window,
11793        cx: &mut Context<Self>,
11794    ) {
11795        self.duplicate(false, false, window, cx);
11796    }
11797
11798    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11800        if self.mode.is_single_line() {
11801            cx.propagate();
11802            return;
11803        }
11804
11805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11806        let buffer = self.buffer.read(cx).snapshot(cx);
11807
11808        let mut edits = Vec::new();
11809        let mut unfold_ranges = Vec::new();
11810        let mut refold_creases = Vec::new();
11811
11812        let selections = self.selections.all::<Point>(cx);
11813        let mut selections = selections.iter().peekable();
11814        let mut contiguous_row_selections = Vec::new();
11815        let mut new_selections = Vec::new();
11816
11817        while let Some(selection) = selections.next() {
11818            // Find all the selections that span a contiguous row range
11819            let (start_row, end_row) = consume_contiguous_rows(
11820                &mut contiguous_row_selections,
11821                selection,
11822                &display_map,
11823                &mut selections,
11824            );
11825
11826            // Move the text spanned by the row range to be before the line preceding the row range
11827            if start_row.0 > 0 {
11828                let range_to_move = Point::new(
11829                    start_row.previous_row().0,
11830                    buffer.line_len(start_row.previous_row()),
11831                )
11832                    ..Point::new(
11833                        end_row.previous_row().0,
11834                        buffer.line_len(end_row.previous_row()),
11835                    );
11836                let insertion_point = display_map
11837                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11838                    .0;
11839
11840                // Don't move lines across excerpts
11841                if buffer
11842                    .excerpt_containing(insertion_point..range_to_move.end)
11843                    .is_some()
11844                {
11845                    let text = buffer
11846                        .text_for_range(range_to_move.clone())
11847                        .flat_map(|s| s.chars())
11848                        .skip(1)
11849                        .chain(['\n'])
11850                        .collect::<String>();
11851
11852                    edits.push((
11853                        buffer.anchor_after(range_to_move.start)
11854                            ..buffer.anchor_before(range_to_move.end),
11855                        String::new(),
11856                    ));
11857                    let insertion_anchor = buffer.anchor_after(insertion_point);
11858                    edits.push((insertion_anchor..insertion_anchor, text));
11859
11860                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11861
11862                    // Move selections up
11863                    new_selections.extend(contiguous_row_selections.drain(..).map(
11864                        |mut selection| {
11865                            selection.start.row -= row_delta;
11866                            selection.end.row -= row_delta;
11867                            selection
11868                        },
11869                    ));
11870
11871                    // Move folds up
11872                    unfold_ranges.push(range_to_move.clone());
11873                    for fold in display_map.folds_in_range(
11874                        buffer.anchor_before(range_to_move.start)
11875                            ..buffer.anchor_after(range_to_move.end),
11876                    ) {
11877                        let mut start = fold.range.start.to_point(&buffer);
11878                        let mut end = fold.range.end.to_point(&buffer);
11879                        start.row -= row_delta;
11880                        end.row -= row_delta;
11881                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11882                    }
11883                }
11884            }
11885
11886            // If we didn't move line(s), preserve the existing selections
11887            new_selections.append(&mut contiguous_row_selections);
11888        }
11889
11890        self.transact(window, cx, |this, window, cx| {
11891            this.unfold_ranges(&unfold_ranges, true, true, cx);
11892            this.buffer.update(cx, |buffer, cx| {
11893                for (range, text) in edits {
11894                    buffer.edit([(range, text)], None, cx);
11895                }
11896            });
11897            this.fold_creases(refold_creases, true, window, cx);
11898            this.change_selections(Default::default(), window, cx, |s| {
11899                s.select(new_selections);
11900            })
11901        });
11902    }
11903
11904    pub fn move_line_down(
11905        &mut self,
11906        _: &MoveLineDown,
11907        window: &mut Window,
11908        cx: &mut Context<Self>,
11909    ) {
11910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11911        if self.mode.is_single_line() {
11912            cx.propagate();
11913            return;
11914        }
11915
11916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11917        let buffer = self.buffer.read(cx).snapshot(cx);
11918
11919        let mut edits = Vec::new();
11920        let mut unfold_ranges = Vec::new();
11921        let mut refold_creases = Vec::new();
11922
11923        let selections = self.selections.all::<Point>(cx);
11924        let mut selections = selections.iter().peekable();
11925        let mut contiguous_row_selections = Vec::new();
11926        let mut new_selections = Vec::new();
11927
11928        while let Some(selection) = selections.next() {
11929            // Find all the selections that span a contiguous row range
11930            let (start_row, end_row) = consume_contiguous_rows(
11931                &mut contiguous_row_selections,
11932                selection,
11933                &display_map,
11934                &mut selections,
11935            );
11936
11937            // Move the text spanned by the row range to be after the last line of the row range
11938            if end_row.0 <= buffer.max_point().row {
11939                let range_to_move =
11940                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11941                let insertion_point = display_map
11942                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11943                    .0;
11944
11945                // Don't move lines across excerpt boundaries
11946                if buffer
11947                    .excerpt_containing(range_to_move.start..insertion_point)
11948                    .is_some()
11949                {
11950                    let mut text = String::from("\n");
11951                    text.extend(buffer.text_for_range(range_to_move.clone()));
11952                    text.pop(); // Drop trailing newline
11953                    edits.push((
11954                        buffer.anchor_after(range_to_move.start)
11955                            ..buffer.anchor_before(range_to_move.end),
11956                        String::new(),
11957                    ));
11958                    let insertion_anchor = buffer.anchor_after(insertion_point);
11959                    edits.push((insertion_anchor..insertion_anchor, text));
11960
11961                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11962
11963                    // Move selections down
11964                    new_selections.extend(contiguous_row_selections.drain(..).map(
11965                        |mut selection| {
11966                            selection.start.row += row_delta;
11967                            selection.end.row += row_delta;
11968                            selection
11969                        },
11970                    ));
11971
11972                    // Move folds down
11973                    unfold_ranges.push(range_to_move.clone());
11974                    for fold in display_map.folds_in_range(
11975                        buffer.anchor_before(range_to_move.start)
11976                            ..buffer.anchor_after(range_to_move.end),
11977                    ) {
11978                        let mut start = fold.range.start.to_point(&buffer);
11979                        let mut end = fold.range.end.to_point(&buffer);
11980                        start.row += row_delta;
11981                        end.row += row_delta;
11982                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11983                    }
11984                }
11985            }
11986
11987            // If we didn't move line(s), preserve the existing selections
11988            new_selections.append(&mut contiguous_row_selections);
11989        }
11990
11991        self.transact(window, cx, |this, window, cx| {
11992            this.unfold_ranges(&unfold_ranges, true, true, cx);
11993            this.buffer.update(cx, |buffer, cx| {
11994                for (range, text) in edits {
11995                    buffer.edit([(range, text)], None, cx);
11996                }
11997            });
11998            this.fold_creases(refold_creases, true, window, cx);
11999            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12000        });
12001    }
12002
12003    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12004        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12005        let text_layout_details = &self.text_layout_details(window);
12006        self.transact(window, cx, |this, window, cx| {
12007            let edits = this.change_selections(Default::default(), window, cx, |s| {
12008                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12009                s.move_with(|display_map, selection| {
12010                    if !selection.is_empty() {
12011                        return;
12012                    }
12013
12014                    let mut head = selection.head();
12015                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12016                    if head.column() == display_map.line_len(head.row()) {
12017                        transpose_offset = display_map
12018                            .buffer_snapshot()
12019                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12020                    }
12021
12022                    if transpose_offset == 0 {
12023                        return;
12024                    }
12025
12026                    *head.column_mut() += 1;
12027                    head = display_map.clip_point(head, Bias::Right);
12028                    let goal = SelectionGoal::HorizontalPosition(
12029                        display_map
12030                            .x_for_display_point(head, text_layout_details)
12031                            .into(),
12032                    );
12033                    selection.collapse_to(head, goal);
12034
12035                    let transpose_start = display_map
12036                        .buffer_snapshot()
12037                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12038                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12039                        let transpose_end = display_map
12040                            .buffer_snapshot()
12041                            .clip_offset(transpose_offset + 1, Bias::Right);
12042                        if let Some(ch) = display_map
12043                            .buffer_snapshot()
12044                            .chars_at(transpose_start)
12045                            .next()
12046                        {
12047                            edits.push((transpose_start..transpose_offset, String::new()));
12048                            edits.push((transpose_end..transpose_end, ch.to_string()));
12049                        }
12050                    }
12051                });
12052                edits
12053            });
12054            this.buffer
12055                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12056            let selections = this.selections.all::<usize>(cx);
12057            this.change_selections(Default::default(), window, cx, |s| {
12058                s.select(selections);
12059            });
12060        });
12061    }
12062
12063    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12065        if self.mode.is_single_line() {
12066            cx.propagate();
12067            return;
12068        }
12069
12070        self.rewrap_impl(RewrapOptions::default(), cx)
12071    }
12072
12073    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12074        let buffer = self.buffer.read(cx).snapshot(cx);
12075        let selections = self.selections.all::<Point>(cx);
12076
12077        #[derive(Clone, Debug, PartialEq)]
12078        enum CommentFormat {
12079            /// single line comment, with prefix for line
12080            Line(String),
12081            /// single line within a block comment, with prefix for line
12082            BlockLine(String),
12083            /// a single line of a block comment that includes the initial delimiter
12084            BlockCommentWithStart(BlockCommentConfig),
12085            /// a single line of a block comment that includes the ending delimiter
12086            BlockCommentWithEnd(BlockCommentConfig),
12087        }
12088
12089        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12090        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12091            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12092                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12093                .peekable();
12094
12095            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12096                row
12097            } else {
12098                return Vec::new();
12099            };
12100
12101            let language_settings = buffer.language_settings_at(selection.head(), cx);
12102            let language_scope = buffer.language_scope_at(selection.head());
12103
12104            let indent_and_prefix_for_row =
12105                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12106                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12107                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12108                        &language_scope
12109                    {
12110                        let indent_end = Point::new(row, indent.len);
12111                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12112                        let line_text_after_indent = buffer
12113                            .text_for_range(indent_end..line_end)
12114                            .collect::<String>();
12115
12116                        let is_within_comment_override = buffer
12117                            .language_scope_at(indent_end)
12118                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12119                        let comment_delimiters = if is_within_comment_override {
12120                            // we are within a comment syntax node, but we don't
12121                            // yet know what kind of comment: block, doc or line
12122                            match (
12123                                language_scope.documentation_comment(),
12124                                language_scope.block_comment(),
12125                            ) {
12126                                (Some(config), _) | (_, Some(config))
12127                                    if buffer.contains_str_at(indent_end, &config.start) =>
12128                                {
12129                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12130                                }
12131                                (Some(config), _) | (_, Some(config))
12132                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12133                                {
12134                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12135                                }
12136                                (Some(config), _) | (_, Some(config))
12137                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12138                                {
12139                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12140                                }
12141                                (_, _) => language_scope
12142                                    .line_comment_prefixes()
12143                                    .iter()
12144                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12145                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12146                            }
12147                        } else {
12148                            // we not in an overridden comment node, but we may
12149                            // be within a non-overridden line comment node
12150                            language_scope
12151                                .line_comment_prefixes()
12152                                .iter()
12153                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12154                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12155                        };
12156
12157                        let rewrap_prefix = language_scope
12158                            .rewrap_prefixes()
12159                            .iter()
12160                            .find_map(|prefix_regex| {
12161                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12162                                    if mat.start() == 0 {
12163                                        Some(mat.as_str().to_string())
12164                                    } else {
12165                                        None
12166                                    }
12167                                })
12168                            })
12169                            .flatten();
12170                        (comment_delimiters, rewrap_prefix)
12171                    } else {
12172                        (None, None)
12173                    };
12174                    (indent, comment_prefix, rewrap_prefix)
12175                };
12176
12177            let mut ranges = Vec::new();
12178            let from_empty_selection = selection.is_empty();
12179
12180            let mut current_range_start = first_row;
12181            let mut prev_row = first_row;
12182            let (
12183                mut current_range_indent,
12184                mut current_range_comment_delimiters,
12185                mut current_range_rewrap_prefix,
12186            ) = indent_and_prefix_for_row(first_row);
12187
12188            for row in non_blank_rows_iter.skip(1) {
12189                let has_paragraph_break = row > prev_row + 1;
12190
12191                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12192                    indent_and_prefix_for_row(row);
12193
12194                let has_indent_change = row_indent != current_range_indent;
12195                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12196
12197                let has_boundary_change = has_comment_change
12198                    || row_rewrap_prefix.is_some()
12199                    || (has_indent_change && current_range_comment_delimiters.is_some());
12200
12201                if has_paragraph_break || has_boundary_change {
12202                    ranges.push((
12203                        language_settings.clone(),
12204                        Point::new(current_range_start, 0)
12205                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12206                        current_range_indent,
12207                        current_range_comment_delimiters.clone(),
12208                        current_range_rewrap_prefix.clone(),
12209                        from_empty_selection,
12210                    ));
12211                    current_range_start = row;
12212                    current_range_indent = row_indent;
12213                    current_range_comment_delimiters = row_comment_delimiters;
12214                    current_range_rewrap_prefix = row_rewrap_prefix;
12215                }
12216                prev_row = row;
12217            }
12218
12219            ranges.push((
12220                language_settings.clone(),
12221                Point::new(current_range_start, 0)
12222                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12223                current_range_indent,
12224                current_range_comment_delimiters,
12225                current_range_rewrap_prefix,
12226                from_empty_selection,
12227            ));
12228
12229            ranges
12230        });
12231
12232        let mut edits = Vec::new();
12233        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12234
12235        for (
12236            language_settings,
12237            wrap_range,
12238            mut indent_size,
12239            comment_prefix,
12240            rewrap_prefix,
12241            from_empty_selection,
12242        ) in wrap_ranges
12243        {
12244            let mut start_row = wrap_range.start.row;
12245            let mut end_row = wrap_range.end.row;
12246
12247            // Skip selections that overlap with a range that has already been rewrapped.
12248            let selection_range = start_row..end_row;
12249            if rewrapped_row_ranges
12250                .iter()
12251                .any(|range| range.overlaps(&selection_range))
12252            {
12253                continue;
12254            }
12255
12256            let tab_size = language_settings.tab_size;
12257
12258            let (line_prefix, inside_comment) = match &comment_prefix {
12259                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12260                    (Some(prefix.as_str()), true)
12261                }
12262                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12263                    (Some(prefix.as_ref()), true)
12264                }
12265                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12266                    start: _,
12267                    end: _,
12268                    prefix,
12269                    tab_size,
12270                })) => {
12271                    indent_size.len += tab_size;
12272                    (Some(prefix.as_ref()), true)
12273                }
12274                None => (None, false),
12275            };
12276            let indent_prefix = indent_size.chars().collect::<String>();
12277            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12278
12279            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12280                RewrapBehavior::InComments => inside_comment,
12281                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12282                RewrapBehavior::Anywhere => true,
12283            };
12284
12285            let should_rewrap = options.override_language_settings
12286                || allow_rewrap_based_on_language
12287                || self.hard_wrap.is_some();
12288            if !should_rewrap {
12289                continue;
12290            }
12291
12292            if from_empty_selection {
12293                'expand_upwards: while start_row > 0 {
12294                    let prev_row = start_row - 1;
12295                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12296                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12297                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12298                    {
12299                        start_row = prev_row;
12300                    } else {
12301                        break 'expand_upwards;
12302                    }
12303                }
12304
12305                'expand_downwards: while end_row < buffer.max_point().row {
12306                    let next_row = end_row + 1;
12307                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12308                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12309                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12310                    {
12311                        end_row = next_row;
12312                    } else {
12313                        break 'expand_downwards;
12314                    }
12315                }
12316            }
12317
12318            let start = Point::new(start_row, 0);
12319            let start_offset = ToOffset::to_offset(&start, &buffer);
12320            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12321            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12322            let mut first_line_delimiter = None;
12323            let mut last_line_delimiter = None;
12324            let Some(lines_without_prefixes) = selection_text
12325                .lines()
12326                .enumerate()
12327                .map(|(ix, line)| {
12328                    let line_trimmed = line.trim_start();
12329                    if rewrap_prefix.is_some() && ix > 0 {
12330                        Ok(line_trimmed)
12331                    } else if let Some(
12332                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12333                            start,
12334                            prefix,
12335                            end,
12336                            tab_size,
12337                        })
12338                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12339                            start,
12340                            prefix,
12341                            end,
12342                            tab_size,
12343                        }),
12344                    ) = &comment_prefix
12345                    {
12346                        let line_trimmed = line_trimmed
12347                            .strip_prefix(start.as_ref())
12348                            .map(|s| {
12349                                let mut indent_size = indent_size;
12350                                indent_size.len -= tab_size;
12351                                let indent_prefix: String = indent_size.chars().collect();
12352                                first_line_delimiter = Some((indent_prefix, start));
12353                                s.trim_start()
12354                            })
12355                            .unwrap_or(line_trimmed);
12356                        let line_trimmed = line_trimmed
12357                            .strip_suffix(end.as_ref())
12358                            .map(|s| {
12359                                last_line_delimiter = Some(end);
12360                                s.trim_end()
12361                            })
12362                            .unwrap_or(line_trimmed);
12363                        let line_trimmed = line_trimmed
12364                            .strip_prefix(prefix.as_ref())
12365                            .unwrap_or(line_trimmed);
12366                        Ok(line_trimmed)
12367                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12368                        line_trimmed.strip_prefix(prefix).with_context(|| {
12369                            format!("line did not start with prefix {prefix:?}: {line:?}")
12370                        })
12371                    } else {
12372                        line_trimmed
12373                            .strip_prefix(&line_prefix.trim_start())
12374                            .with_context(|| {
12375                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12376                            })
12377                    }
12378                })
12379                .collect::<Result<Vec<_>, _>>()
12380                .log_err()
12381            else {
12382                continue;
12383            };
12384
12385            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12386                buffer
12387                    .language_settings_at(Point::new(start_row, 0), cx)
12388                    .preferred_line_length as usize
12389            });
12390
12391            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12392                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12393            } else {
12394                line_prefix.clone()
12395            };
12396
12397            let wrapped_text = {
12398                let mut wrapped_text = wrap_with_prefix(
12399                    line_prefix,
12400                    subsequent_lines_prefix,
12401                    lines_without_prefixes.join("\n"),
12402                    wrap_column,
12403                    tab_size,
12404                    options.preserve_existing_whitespace,
12405                );
12406
12407                if let Some((indent, delimiter)) = first_line_delimiter {
12408                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12409                }
12410                if let Some(last_line) = last_line_delimiter {
12411                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12412                }
12413
12414                wrapped_text
12415            };
12416
12417            // TODO: should always use char-based diff while still supporting cursor behavior that
12418            // matches vim.
12419            let mut diff_options = DiffOptions::default();
12420            if options.override_language_settings {
12421                diff_options.max_word_diff_len = 0;
12422                diff_options.max_word_diff_line_count = 0;
12423            } else {
12424                diff_options.max_word_diff_len = usize::MAX;
12425                diff_options.max_word_diff_line_count = usize::MAX;
12426            }
12427
12428            for (old_range, new_text) in
12429                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12430            {
12431                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12432                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12433                edits.push((edit_start..edit_end, new_text));
12434            }
12435
12436            rewrapped_row_ranges.push(start_row..=end_row);
12437        }
12438
12439        self.buffer
12440            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12441    }
12442
12443    pub fn cut_common(
12444        &mut self,
12445        cut_no_selection_line: bool,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) -> ClipboardItem {
12449        let mut text = String::new();
12450        let buffer = self.buffer.read(cx).snapshot(cx);
12451        let mut selections = self.selections.all::<Point>(cx);
12452        let mut clipboard_selections = Vec::with_capacity(selections.len());
12453        {
12454            let max_point = buffer.max_point();
12455            let mut is_first = true;
12456            for selection in &mut selections {
12457                let is_entire_line =
12458                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12459                if is_entire_line {
12460                    selection.start = Point::new(selection.start.row, 0);
12461                    if !selection.is_empty() && selection.end.column == 0 {
12462                        selection.end = cmp::min(max_point, selection.end);
12463                    } else {
12464                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12465                    }
12466                    selection.goal = SelectionGoal::None;
12467                }
12468                if is_first {
12469                    is_first = false;
12470                } else {
12471                    text += "\n";
12472                }
12473                let mut len = 0;
12474                for chunk in buffer.text_for_range(selection.start..selection.end) {
12475                    text.push_str(chunk);
12476                    len += chunk.len();
12477                }
12478                clipboard_selections.push(ClipboardSelection {
12479                    len,
12480                    is_entire_line,
12481                    first_line_indent: buffer
12482                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12483                        .len,
12484                });
12485            }
12486        }
12487
12488        self.transact(window, cx, |this, window, cx| {
12489            this.change_selections(Default::default(), window, cx, |s| {
12490                s.select(selections);
12491            });
12492            this.insert("", window, cx);
12493        });
12494        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12495    }
12496
12497    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12498        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12499        let item = self.cut_common(true, window, cx);
12500        cx.write_to_clipboard(item);
12501    }
12502
12503    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12505        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12506            s.move_with(|snapshot, sel| {
12507                if sel.is_empty() {
12508                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12509                }
12510                if sel.is_empty() {
12511                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12512                }
12513            });
12514        });
12515        let item = self.cut_common(false, window, cx);
12516        cx.set_global(KillRing(item))
12517    }
12518
12519    pub fn kill_ring_yank(
12520        &mut self,
12521        _: &KillRingYank,
12522        window: &mut Window,
12523        cx: &mut Context<Self>,
12524    ) {
12525        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12526        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12527            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12528                (kill_ring.text().to_string(), kill_ring.metadata_json())
12529            } else {
12530                return;
12531            }
12532        } else {
12533            return;
12534        };
12535        self.do_paste(&text, metadata, false, window, cx);
12536    }
12537
12538    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12539        self.do_copy(true, cx);
12540    }
12541
12542    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12543        self.do_copy(false, cx);
12544    }
12545
12546    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12547        let selections = self.selections.all::<Point>(cx);
12548        let buffer = self.buffer.read(cx).read(cx);
12549        let mut text = String::new();
12550
12551        let mut clipboard_selections = Vec::with_capacity(selections.len());
12552        {
12553            let max_point = buffer.max_point();
12554            let mut is_first = true;
12555            for selection in &selections {
12556                let mut start = selection.start;
12557                let mut end = selection.end;
12558                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12559                let mut add_trailing_newline = false;
12560                if is_entire_line {
12561                    start = Point::new(start.row, 0);
12562                    let next_line_start = Point::new(end.row + 1, 0);
12563                    if next_line_start <= max_point {
12564                        end = next_line_start;
12565                    } else {
12566                        // We're on the last line without a trailing newline.
12567                        // Copy to the end of the line and add a newline afterwards.
12568                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12569                        add_trailing_newline = true;
12570                    }
12571                }
12572
12573                let mut trimmed_selections = Vec::new();
12574                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12575                    let row = MultiBufferRow(start.row);
12576                    let first_indent = buffer.indent_size_for_line(row);
12577                    if first_indent.len == 0 || start.column > first_indent.len {
12578                        trimmed_selections.push(start..end);
12579                    } else {
12580                        trimmed_selections.push(
12581                            Point::new(row.0, first_indent.len)
12582                                ..Point::new(row.0, buffer.line_len(row)),
12583                        );
12584                        for row in start.row + 1..=end.row {
12585                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12586                            if row == end.row {
12587                                line_len = end.column;
12588                            }
12589                            if line_len == 0 {
12590                                trimmed_selections
12591                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12592                                continue;
12593                            }
12594                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12595                            if row_indent_size.len >= first_indent.len {
12596                                trimmed_selections.push(
12597                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12598                                );
12599                            } else {
12600                                trimmed_selections.clear();
12601                                trimmed_selections.push(start..end);
12602                                break;
12603                            }
12604                        }
12605                    }
12606                } else {
12607                    trimmed_selections.push(start..end);
12608                }
12609
12610                for trimmed_range in trimmed_selections {
12611                    if is_first {
12612                        is_first = false;
12613                    } else {
12614                        text += "\n";
12615                    }
12616                    let mut len = 0;
12617                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12618                        text.push_str(chunk);
12619                        len += chunk.len();
12620                    }
12621                    if add_trailing_newline {
12622                        text.push('\n');
12623                        len += 1;
12624                    }
12625                    clipboard_selections.push(ClipboardSelection {
12626                        len,
12627                        is_entire_line,
12628                        first_line_indent: buffer
12629                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12630                            .len,
12631                    });
12632                }
12633            }
12634        }
12635
12636        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12637            text,
12638            clipboard_selections,
12639        ));
12640    }
12641
12642    pub fn do_paste(
12643        &mut self,
12644        text: &String,
12645        clipboard_selections: Option<Vec<ClipboardSelection>>,
12646        handle_entire_lines: bool,
12647        window: &mut Window,
12648        cx: &mut Context<Self>,
12649    ) {
12650        if self.read_only(cx) {
12651            return;
12652        }
12653
12654        let clipboard_text = Cow::Borrowed(text.as_str());
12655
12656        self.transact(window, cx, |this, window, cx| {
12657            let had_active_edit_prediction = this.has_active_edit_prediction();
12658            let old_selections = this.selections.all::<usize>(cx);
12659            let cursor_offset = this.selections.last::<usize>(cx).head();
12660
12661            if let Some(mut clipboard_selections) = clipboard_selections {
12662                let all_selections_were_entire_line =
12663                    clipboard_selections.iter().all(|s| s.is_entire_line);
12664                let first_selection_indent_column =
12665                    clipboard_selections.first().map(|s| s.first_line_indent);
12666                if clipboard_selections.len() != old_selections.len() {
12667                    clipboard_selections.drain(..);
12668                }
12669                let mut auto_indent_on_paste = true;
12670
12671                this.buffer.update(cx, |buffer, cx| {
12672                    let snapshot = buffer.read(cx);
12673                    auto_indent_on_paste = snapshot
12674                        .language_settings_at(cursor_offset, cx)
12675                        .auto_indent_on_paste;
12676
12677                    let mut start_offset = 0;
12678                    let mut edits = Vec::new();
12679                    let mut original_indent_columns = Vec::new();
12680                    for (ix, selection) in old_selections.iter().enumerate() {
12681                        let to_insert;
12682                        let entire_line;
12683                        let original_indent_column;
12684                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12685                            let end_offset = start_offset + clipboard_selection.len;
12686                            to_insert = &clipboard_text[start_offset..end_offset];
12687                            entire_line = clipboard_selection.is_entire_line;
12688                            start_offset = end_offset + 1;
12689                            original_indent_column = Some(clipboard_selection.first_line_indent);
12690                        } else {
12691                            to_insert = &*clipboard_text;
12692                            entire_line = all_selections_were_entire_line;
12693                            original_indent_column = first_selection_indent_column
12694                        }
12695
12696                        let (range, to_insert) =
12697                            if selection.is_empty() && handle_entire_lines && entire_line {
12698                                // If the corresponding selection was empty when this slice of the
12699                                // clipboard text was written, then the entire line containing the
12700                                // selection was copied. If this selection is also currently empty,
12701                                // then paste the line before the current line of the buffer.
12702                                let column = selection.start.to_point(&snapshot).column as usize;
12703                                let line_start = selection.start - column;
12704                                (line_start..line_start, Cow::Borrowed(to_insert))
12705                            } else {
12706                                let language = snapshot.language_at(selection.head());
12707                                let range = selection.range();
12708                                if let Some(language) = language
12709                                    && language.name() == "Markdown".into()
12710                                {
12711                                    edit_for_markdown_paste(
12712                                        &snapshot,
12713                                        range,
12714                                        to_insert,
12715                                        url::Url::parse(to_insert).ok(),
12716                                    )
12717                                } else {
12718                                    (range, Cow::Borrowed(to_insert))
12719                                }
12720                            };
12721
12722                        edits.push((range, to_insert));
12723                        original_indent_columns.push(original_indent_column);
12724                    }
12725                    drop(snapshot);
12726
12727                    buffer.edit(
12728                        edits,
12729                        if auto_indent_on_paste {
12730                            Some(AutoindentMode::Block {
12731                                original_indent_columns,
12732                            })
12733                        } else {
12734                            None
12735                        },
12736                        cx,
12737                    );
12738                });
12739
12740                let selections = this.selections.all::<usize>(cx);
12741                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12742            } else {
12743                let url = url::Url::parse(&clipboard_text).ok();
12744
12745                let auto_indent_mode = if !clipboard_text.is_empty() {
12746                    Some(AutoindentMode::Block {
12747                        original_indent_columns: Vec::new(),
12748                    })
12749                } else {
12750                    None
12751                };
12752
12753                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12754                    let snapshot = buffer.snapshot(cx);
12755
12756                    let anchors = old_selections
12757                        .iter()
12758                        .map(|s| {
12759                            let anchor = snapshot.anchor_after(s.head());
12760                            s.map(|_| anchor)
12761                        })
12762                        .collect::<Vec<_>>();
12763
12764                    let mut edits = Vec::new();
12765
12766                    for selection in old_selections.iter() {
12767                        let language = snapshot.language_at(selection.head());
12768                        let range = selection.range();
12769
12770                        let (edit_range, edit_text) = if let Some(language) = language
12771                            && language.name() == "Markdown".into()
12772                        {
12773                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12774                        } else {
12775                            (range, clipboard_text.clone())
12776                        };
12777
12778                        edits.push((edit_range, edit_text));
12779                    }
12780
12781                    drop(snapshot);
12782                    buffer.edit(edits, auto_indent_mode, cx);
12783
12784                    anchors
12785                });
12786
12787                this.change_selections(Default::default(), window, cx, |s| {
12788                    s.select_anchors(selection_anchors);
12789                });
12790            }
12791
12792            let trigger_in_words =
12793                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12794
12795            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12796        });
12797    }
12798
12799    pub fn diff_clipboard_with_selection(
12800        &mut self,
12801        _: &DiffClipboardWithSelection,
12802        window: &mut Window,
12803        cx: &mut Context<Self>,
12804    ) {
12805        let selections = self.selections.all::<usize>(cx);
12806
12807        if selections.is_empty() {
12808            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12809            return;
12810        };
12811
12812        let clipboard_text = match cx.read_from_clipboard() {
12813            Some(item) => match item.entries().first() {
12814                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12815                _ => None,
12816            },
12817            None => None,
12818        };
12819
12820        let Some(clipboard_text) = clipboard_text else {
12821            log::warn!("Clipboard doesn't contain text.");
12822            return;
12823        };
12824
12825        window.dispatch_action(
12826            Box::new(DiffClipboardWithSelectionData {
12827                clipboard_text,
12828                editor: cx.entity(),
12829            }),
12830            cx,
12831        );
12832    }
12833
12834    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12835        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12836        if let Some(item) = cx.read_from_clipboard() {
12837            let entries = item.entries();
12838
12839            match entries.first() {
12840                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12841                // of all the pasted entries.
12842                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12843                    .do_paste(
12844                        clipboard_string.text(),
12845                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12846                        true,
12847                        window,
12848                        cx,
12849                    ),
12850                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12851            }
12852        }
12853    }
12854
12855    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12856        if self.read_only(cx) {
12857            return;
12858        }
12859
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12861
12862        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12863            if let Some((selections, _)) =
12864                self.selection_history.transaction(transaction_id).cloned()
12865            {
12866                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12867                    s.select_anchors(selections.to_vec());
12868                });
12869            } else {
12870                log::error!(
12871                    "No entry in selection_history found for undo. \
12872                     This may correspond to a bug where undo does not update the selection. \
12873                     If this is occurring, please add details to \
12874                     https://github.com/zed-industries/zed/issues/22692"
12875                );
12876            }
12877            self.request_autoscroll(Autoscroll::fit(), cx);
12878            self.unmark_text(window, cx);
12879            self.refresh_edit_prediction(true, false, window, cx);
12880            cx.emit(EditorEvent::Edited { transaction_id });
12881            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12882        }
12883    }
12884
12885    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12886        if self.read_only(cx) {
12887            return;
12888        }
12889
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12891
12892        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12893            if let Some((_, Some(selections))) =
12894                self.selection_history.transaction(transaction_id).cloned()
12895            {
12896                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12897                    s.select_anchors(selections.to_vec());
12898                });
12899            } else {
12900                log::error!(
12901                    "No entry in selection_history found for redo. \
12902                     This may correspond to a bug where undo does not update the selection. \
12903                     If this is occurring, please add details to \
12904                     https://github.com/zed-industries/zed/issues/22692"
12905                );
12906            }
12907            self.request_autoscroll(Autoscroll::fit(), cx);
12908            self.unmark_text(window, cx);
12909            self.refresh_edit_prediction(true, false, window, cx);
12910            cx.emit(EditorEvent::Edited { transaction_id });
12911        }
12912    }
12913
12914    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12915        self.buffer
12916            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12917    }
12918
12919    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12920        self.buffer
12921            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12922    }
12923
12924    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926        self.change_selections(Default::default(), window, cx, |s| {
12927            s.move_with(|map, selection| {
12928                let cursor = if selection.is_empty() {
12929                    movement::left(map, selection.start)
12930                } else {
12931                    selection.start
12932                };
12933                selection.collapse_to(cursor, SelectionGoal::None);
12934            });
12935        })
12936    }
12937
12938    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12940        self.change_selections(Default::default(), window, cx, |s| {
12941            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12942        })
12943    }
12944
12945    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12947        self.change_selections(Default::default(), window, cx, |s| {
12948            s.move_with(|map, selection| {
12949                let cursor = if selection.is_empty() {
12950                    movement::right(map, selection.end)
12951                } else {
12952                    selection.end
12953                };
12954                selection.collapse_to(cursor, SelectionGoal::None)
12955            });
12956        })
12957    }
12958
12959    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12961        self.change_selections(Default::default(), window, cx, |s| {
12962            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12963        });
12964    }
12965
12966    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12967        if self.take_rename(true, window, cx).is_some() {
12968            return;
12969        }
12970
12971        if self.mode.is_single_line() {
12972            cx.propagate();
12973            return;
12974        }
12975
12976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12977
12978        let text_layout_details = &self.text_layout_details(window);
12979        let selection_count = self.selections.count();
12980        let first_selection = self.selections.first_anchor();
12981
12982        self.change_selections(Default::default(), window, cx, |s| {
12983            s.move_with(|map, selection| {
12984                if !selection.is_empty() {
12985                    selection.goal = SelectionGoal::None;
12986                }
12987                let (cursor, goal) = movement::up(
12988                    map,
12989                    selection.start,
12990                    selection.goal,
12991                    false,
12992                    text_layout_details,
12993                );
12994                selection.collapse_to(cursor, goal);
12995            });
12996        });
12997
12998        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12999        {
13000            cx.propagate();
13001        }
13002    }
13003
13004    pub fn move_up_by_lines(
13005        &mut self,
13006        action: &MoveUpByLines,
13007        window: &mut Window,
13008        cx: &mut Context<Self>,
13009    ) {
13010        if self.take_rename(true, window, cx).is_some() {
13011            return;
13012        }
13013
13014        if self.mode.is_single_line() {
13015            cx.propagate();
13016            return;
13017        }
13018
13019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13020
13021        let text_layout_details = &self.text_layout_details(window);
13022
13023        self.change_selections(Default::default(), window, cx, |s| {
13024            s.move_with(|map, selection| {
13025                if !selection.is_empty() {
13026                    selection.goal = SelectionGoal::None;
13027                }
13028                let (cursor, goal) = movement::up_by_rows(
13029                    map,
13030                    selection.start,
13031                    action.lines,
13032                    selection.goal,
13033                    false,
13034                    text_layout_details,
13035                );
13036                selection.collapse_to(cursor, goal);
13037            });
13038        })
13039    }
13040
13041    pub fn move_down_by_lines(
13042        &mut self,
13043        action: &MoveDownByLines,
13044        window: &mut Window,
13045        cx: &mut Context<Self>,
13046    ) {
13047        if self.take_rename(true, window, cx).is_some() {
13048            return;
13049        }
13050
13051        if self.mode.is_single_line() {
13052            cx.propagate();
13053            return;
13054        }
13055
13056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13057
13058        let text_layout_details = &self.text_layout_details(window);
13059
13060        self.change_selections(Default::default(), window, cx, |s| {
13061            s.move_with(|map, selection| {
13062                if !selection.is_empty() {
13063                    selection.goal = SelectionGoal::None;
13064                }
13065                let (cursor, goal) = movement::down_by_rows(
13066                    map,
13067                    selection.start,
13068                    action.lines,
13069                    selection.goal,
13070                    false,
13071                    text_layout_details,
13072                );
13073                selection.collapse_to(cursor, goal);
13074            });
13075        })
13076    }
13077
13078    pub fn select_down_by_lines(
13079        &mut self,
13080        action: &SelectDownByLines,
13081        window: &mut Window,
13082        cx: &mut Context<Self>,
13083    ) {
13084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13085        let text_layout_details = &self.text_layout_details(window);
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_heads_with(|map, head, goal| {
13088                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13089            })
13090        })
13091    }
13092
13093    pub fn select_up_by_lines(
13094        &mut self,
13095        action: &SelectUpByLines,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100        let text_layout_details = &self.text_layout_details(window);
13101        self.change_selections(Default::default(), window, cx, |s| {
13102            s.move_heads_with(|map, head, goal| {
13103                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13104            })
13105        })
13106    }
13107
13108    pub fn select_page_up(
13109        &mut self,
13110        _: &SelectPageUp,
13111        window: &mut Window,
13112        cx: &mut Context<Self>,
13113    ) {
13114        let Some(row_count) = self.visible_row_count() else {
13115            return;
13116        };
13117
13118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13119
13120        let text_layout_details = &self.text_layout_details(window);
13121
13122        self.change_selections(Default::default(), window, cx, |s| {
13123            s.move_heads_with(|map, head, goal| {
13124                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13125            })
13126        })
13127    }
13128
13129    pub fn move_page_up(
13130        &mut self,
13131        action: &MovePageUp,
13132        window: &mut Window,
13133        cx: &mut Context<Self>,
13134    ) {
13135        if self.take_rename(true, window, cx).is_some() {
13136            return;
13137        }
13138
13139        if self
13140            .context_menu
13141            .borrow_mut()
13142            .as_mut()
13143            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13144            .unwrap_or(false)
13145        {
13146            return;
13147        }
13148
13149        if matches!(self.mode, EditorMode::SingleLine) {
13150            cx.propagate();
13151            return;
13152        }
13153
13154        let Some(row_count) = self.visible_row_count() else {
13155            return;
13156        };
13157
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159
13160        let effects = if action.center_cursor {
13161            SelectionEffects::scroll(Autoscroll::center())
13162        } else {
13163            SelectionEffects::default()
13164        };
13165
13166        let text_layout_details = &self.text_layout_details(window);
13167
13168        self.change_selections(effects, window, cx, |s| {
13169            s.move_with(|map, selection| {
13170                if !selection.is_empty() {
13171                    selection.goal = SelectionGoal::None;
13172                }
13173                let (cursor, goal) = movement::up_by_rows(
13174                    map,
13175                    selection.end,
13176                    row_count,
13177                    selection.goal,
13178                    false,
13179                    text_layout_details,
13180                );
13181                selection.collapse_to(cursor, goal);
13182            });
13183        });
13184    }
13185
13186    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13188        let text_layout_details = &self.text_layout_details(window);
13189        self.change_selections(Default::default(), window, cx, |s| {
13190            s.move_heads_with(|map, head, goal| {
13191                movement::up(map, head, goal, false, text_layout_details)
13192            })
13193        })
13194    }
13195
13196    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13197        self.take_rename(true, window, cx);
13198
13199        if self.mode.is_single_line() {
13200            cx.propagate();
13201            return;
13202        }
13203
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13205
13206        let text_layout_details = &self.text_layout_details(window);
13207        let selection_count = self.selections.count();
13208        let first_selection = self.selections.first_anchor();
13209
13210        self.change_selections(Default::default(), window, cx, |s| {
13211            s.move_with(|map, selection| {
13212                if !selection.is_empty() {
13213                    selection.goal = SelectionGoal::None;
13214                }
13215                let (cursor, goal) = movement::down(
13216                    map,
13217                    selection.end,
13218                    selection.goal,
13219                    false,
13220                    text_layout_details,
13221                );
13222                selection.collapse_to(cursor, goal);
13223            });
13224        });
13225
13226        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13227        {
13228            cx.propagate();
13229        }
13230    }
13231
13232    pub fn select_page_down(
13233        &mut self,
13234        _: &SelectPageDown,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        let Some(row_count) = self.visible_row_count() else {
13239            return;
13240        };
13241
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243
13244        let text_layout_details = &self.text_layout_details(window);
13245
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_heads_with(|map, head, goal| {
13248                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13249            })
13250        })
13251    }
13252
13253    pub fn move_page_down(
13254        &mut self,
13255        action: &MovePageDown,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        if self.take_rename(true, window, cx).is_some() {
13260            return;
13261        }
13262
13263        if self
13264            .context_menu
13265            .borrow_mut()
13266            .as_mut()
13267            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13268            .unwrap_or(false)
13269        {
13270            return;
13271        }
13272
13273        if matches!(self.mode, EditorMode::SingleLine) {
13274            cx.propagate();
13275            return;
13276        }
13277
13278        let Some(row_count) = self.visible_row_count() else {
13279            return;
13280        };
13281
13282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13283
13284        let effects = if action.center_cursor {
13285            SelectionEffects::scroll(Autoscroll::center())
13286        } else {
13287            SelectionEffects::default()
13288        };
13289
13290        let text_layout_details = &self.text_layout_details(window);
13291        self.change_selections(effects, window, cx, |s| {
13292            s.move_with(|map, selection| {
13293                if !selection.is_empty() {
13294                    selection.goal = SelectionGoal::None;
13295                }
13296                let (cursor, goal) = movement::down_by_rows(
13297                    map,
13298                    selection.end,
13299                    row_count,
13300                    selection.goal,
13301                    false,
13302                    text_layout_details,
13303                );
13304                selection.collapse_to(cursor, goal);
13305            });
13306        });
13307    }
13308
13309    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13311        let text_layout_details = &self.text_layout_details(window);
13312        self.change_selections(Default::default(), window, cx, |s| {
13313            s.move_heads_with(|map, head, goal| {
13314                movement::down(map, head, goal, false, text_layout_details)
13315            })
13316        });
13317    }
13318
13319    pub fn context_menu_first(
13320        &mut self,
13321        _: &ContextMenuFirst,
13322        window: &mut Window,
13323        cx: &mut Context<Self>,
13324    ) {
13325        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13326            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13327        }
13328    }
13329
13330    pub fn context_menu_prev(
13331        &mut self,
13332        _: &ContextMenuPrevious,
13333        window: &mut Window,
13334        cx: &mut Context<Self>,
13335    ) {
13336        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13337            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13338        }
13339    }
13340
13341    pub fn context_menu_next(
13342        &mut self,
13343        _: &ContextMenuNext,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13348            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13349        }
13350    }
13351
13352    pub fn context_menu_last(
13353        &mut self,
13354        _: &ContextMenuLast,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13359            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13360        }
13361    }
13362
13363    pub fn signature_help_prev(
13364        &mut self,
13365        _: &SignatureHelpPrevious,
13366        _: &mut Window,
13367        cx: &mut Context<Self>,
13368    ) {
13369        if let Some(popover) = self.signature_help_state.popover_mut() {
13370            if popover.current_signature == 0 {
13371                popover.current_signature = popover.signatures.len() - 1;
13372            } else {
13373                popover.current_signature -= 1;
13374            }
13375            cx.notify();
13376        }
13377    }
13378
13379    pub fn signature_help_next(
13380        &mut self,
13381        _: &SignatureHelpNext,
13382        _: &mut Window,
13383        cx: &mut Context<Self>,
13384    ) {
13385        if let Some(popover) = self.signature_help_state.popover_mut() {
13386            if popover.current_signature + 1 == popover.signatures.len() {
13387                popover.current_signature = 0;
13388            } else {
13389                popover.current_signature += 1;
13390            }
13391            cx.notify();
13392        }
13393    }
13394
13395    pub fn move_to_previous_word_start(
13396        &mut self,
13397        _: &MoveToPreviousWordStart,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13402        self.change_selections(Default::default(), window, cx, |s| {
13403            s.move_cursors_with(|map, head, _| {
13404                (
13405                    movement::previous_word_start(map, head),
13406                    SelectionGoal::None,
13407                )
13408            });
13409        })
13410    }
13411
13412    pub fn move_to_previous_subword_start(
13413        &mut self,
13414        _: &MoveToPreviousSubwordStart,
13415        window: &mut Window,
13416        cx: &mut Context<Self>,
13417    ) {
13418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13419        self.change_selections(Default::default(), window, cx, |s| {
13420            s.move_cursors_with(|map, head, _| {
13421                (
13422                    movement::previous_subword_start(map, head),
13423                    SelectionGoal::None,
13424                )
13425            });
13426        })
13427    }
13428
13429    pub fn select_to_previous_word_start(
13430        &mut self,
13431        _: &SelectToPreviousWordStart,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436        self.change_selections(Default::default(), window, cx, |s| {
13437            s.move_heads_with(|map, head, _| {
13438                (
13439                    movement::previous_word_start(map, head),
13440                    SelectionGoal::None,
13441                )
13442            });
13443        })
13444    }
13445
13446    pub fn select_to_previous_subword_start(
13447        &mut self,
13448        _: &SelectToPreviousSubwordStart,
13449        window: &mut Window,
13450        cx: &mut Context<Self>,
13451    ) {
13452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13453        self.change_selections(Default::default(), window, cx, |s| {
13454            s.move_heads_with(|map, head, _| {
13455                (
13456                    movement::previous_subword_start(map, head),
13457                    SelectionGoal::None,
13458                )
13459            });
13460        })
13461    }
13462
13463    pub fn delete_to_previous_word_start(
13464        &mut self,
13465        action: &DeleteToPreviousWordStart,
13466        window: &mut Window,
13467        cx: &mut Context<Self>,
13468    ) {
13469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13470        self.transact(window, cx, |this, window, cx| {
13471            this.select_autoclose_pair(window, cx);
13472            this.change_selections(Default::default(), window, cx, |s| {
13473                s.move_with(|map, selection| {
13474                    if selection.is_empty() {
13475                        let mut cursor = if action.ignore_newlines {
13476                            movement::previous_word_start(map, selection.head())
13477                        } else {
13478                            movement::previous_word_start_or_newline(map, selection.head())
13479                        };
13480                        cursor = movement::adjust_greedy_deletion(
13481                            map,
13482                            selection.head(),
13483                            cursor,
13484                            action.ignore_brackets,
13485                        );
13486                        selection.set_head(cursor, SelectionGoal::None);
13487                    }
13488                });
13489            });
13490            this.insert("", window, cx);
13491        });
13492    }
13493
13494    pub fn delete_to_previous_subword_start(
13495        &mut self,
13496        _: &DeleteToPreviousSubwordStart,
13497        window: &mut Window,
13498        cx: &mut Context<Self>,
13499    ) {
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13501        self.transact(window, cx, |this, window, cx| {
13502            this.select_autoclose_pair(window, cx);
13503            this.change_selections(Default::default(), window, cx, |s| {
13504                s.move_with(|map, selection| {
13505                    if selection.is_empty() {
13506                        let mut cursor = movement::previous_subword_start(map, selection.head());
13507                        cursor =
13508                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13509                        selection.set_head(cursor, SelectionGoal::None);
13510                    }
13511                });
13512            });
13513            this.insert("", window, cx);
13514        });
13515    }
13516
13517    pub fn move_to_next_word_end(
13518        &mut self,
13519        _: &MoveToNextWordEnd,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13524        self.change_selections(Default::default(), window, cx, |s| {
13525            s.move_cursors_with(|map, head, _| {
13526                (movement::next_word_end(map, head), SelectionGoal::None)
13527            });
13528        })
13529    }
13530
13531    pub fn move_to_next_subword_end(
13532        &mut self,
13533        _: &MoveToNextSubwordEnd,
13534        window: &mut Window,
13535        cx: &mut Context<Self>,
13536    ) {
13537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13538        self.change_selections(Default::default(), window, cx, |s| {
13539            s.move_cursors_with(|map, head, _| {
13540                (movement::next_subword_end(map, head), SelectionGoal::None)
13541            });
13542        })
13543    }
13544
13545    pub fn select_to_next_word_end(
13546        &mut self,
13547        _: &SelectToNextWordEnd,
13548        window: &mut Window,
13549        cx: &mut Context<Self>,
13550    ) {
13551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.move_heads_with(|map, head, _| {
13554                (movement::next_word_end(map, head), SelectionGoal::None)
13555            });
13556        })
13557    }
13558
13559    pub fn select_to_next_subword_end(
13560        &mut self,
13561        _: &SelectToNextSubwordEnd,
13562        window: &mut Window,
13563        cx: &mut Context<Self>,
13564    ) {
13565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13566        self.change_selections(Default::default(), window, cx, |s| {
13567            s.move_heads_with(|map, head, _| {
13568                (movement::next_subword_end(map, head), SelectionGoal::None)
13569            });
13570        })
13571    }
13572
13573    pub fn delete_to_next_word_end(
13574        &mut self,
13575        action: &DeleteToNextWordEnd,
13576        window: &mut Window,
13577        cx: &mut Context<Self>,
13578    ) {
13579        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13580        self.transact(window, cx, |this, window, cx| {
13581            this.change_selections(Default::default(), window, cx, |s| {
13582                s.move_with(|map, selection| {
13583                    if selection.is_empty() {
13584                        let mut cursor = if action.ignore_newlines {
13585                            movement::next_word_end(map, selection.head())
13586                        } else {
13587                            movement::next_word_end_or_newline(map, selection.head())
13588                        };
13589                        cursor = movement::adjust_greedy_deletion(
13590                            map,
13591                            selection.head(),
13592                            cursor,
13593                            action.ignore_brackets,
13594                        );
13595                        selection.set_head(cursor, SelectionGoal::None);
13596                    }
13597                });
13598            });
13599            this.insert("", window, cx);
13600        });
13601    }
13602
13603    pub fn delete_to_next_subword_end(
13604        &mut self,
13605        _: &DeleteToNextSubwordEnd,
13606        window: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13610        self.transact(window, cx, |this, window, cx| {
13611            this.change_selections(Default::default(), window, cx, |s| {
13612                s.move_with(|map, selection| {
13613                    if selection.is_empty() {
13614                        let mut cursor = movement::next_subword_end(map, selection.head());
13615                        cursor =
13616                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13617                        selection.set_head(cursor, SelectionGoal::None);
13618                    }
13619                });
13620            });
13621            this.insert("", window, cx);
13622        });
13623    }
13624
13625    pub fn move_to_beginning_of_line(
13626        &mut self,
13627        action: &MoveToBeginningOfLine,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_cursors_with(|map, head, _| {
13634                (
13635                    movement::indented_line_beginning(
13636                        map,
13637                        head,
13638                        action.stop_at_soft_wraps,
13639                        action.stop_at_indent,
13640                    ),
13641                    SelectionGoal::None,
13642                )
13643            });
13644        })
13645    }
13646
13647    pub fn select_to_beginning_of_line(
13648        &mut self,
13649        action: &SelectToBeginningOfLine,
13650        window: &mut Window,
13651        cx: &mut Context<Self>,
13652    ) {
13653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.move_heads_with(|map, head, _| {
13656                (
13657                    movement::indented_line_beginning(
13658                        map,
13659                        head,
13660                        action.stop_at_soft_wraps,
13661                        action.stop_at_indent,
13662                    ),
13663                    SelectionGoal::None,
13664                )
13665            });
13666        });
13667    }
13668
13669    pub fn delete_to_beginning_of_line(
13670        &mut self,
13671        action: &DeleteToBeginningOfLine,
13672        window: &mut Window,
13673        cx: &mut Context<Self>,
13674    ) {
13675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13676        self.transact(window, cx, |this, window, cx| {
13677            this.change_selections(Default::default(), window, cx, |s| {
13678                s.move_with(|_, selection| {
13679                    selection.reversed = true;
13680                });
13681            });
13682
13683            this.select_to_beginning_of_line(
13684                &SelectToBeginningOfLine {
13685                    stop_at_soft_wraps: false,
13686                    stop_at_indent: action.stop_at_indent,
13687                },
13688                window,
13689                cx,
13690            );
13691            this.backspace(&Backspace, window, cx);
13692        });
13693    }
13694
13695    pub fn move_to_end_of_line(
13696        &mut self,
13697        action: &MoveToEndOfLine,
13698        window: &mut Window,
13699        cx: &mut Context<Self>,
13700    ) {
13701        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13702        self.change_selections(Default::default(), window, cx, |s| {
13703            s.move_cursors_with(|map, head, _| {
13704                (
13705                    movement::line_end(map, head, action.stop_at_soft_wraps),
13706                    SelectionGoal::None,
13707                )
13708            });
13709        })
13710    }
13711
13712    pub fn select_to_end_of_line(
13713        &mut self,
13714        action: &SelectToEndOfLine,
13715        window: &mut Window,
13716        cx: &mut Context<Self>,
13717    ) {
13718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.move_heads_with(|map, head, _| {
13721                (
13722                    movement::line_end(map, head, action.stop_at_soft_wraps),
13723                    SelectionGoal::None,
13724                )
13725            });
13726        })
13727    }
13728
13729    pub fn delete_to_end_of_line(
13730        &mut self,
13731        _: &DeleteToEndOfLine,
13732        window: &mut Window,
13733        cx: &mut Context<Self>,
13734    ) {
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13736        self.transact(window, cx, |this, window, cx| {
13737            this.select_to_end_of_line(
13738                &SelectToEndOfLine {
13739                    stop_at_soft_wraps: false,
13740                },
13741                window,
13742                cx,
13743            );
13744            this.delete(&Delete, window, cx);
13745        });
13746    }
13747
13748    pub fn cut_to_end_of_line(
13749        &mut self,
13750        action: &CutToEndOfLine,
13751        window: &mut Window,
13752        cx: &mut Context<Self>,
13753    ) {
13754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13755        self.transact(window, cx, |this, window, cx| {
13756            this.select_to_end_of_line(
13757                &SelectToEndOfLine {
13758                    stop_at_soft_wraps: false,
13759                },
13760                window,
13761                cx,
13762            );
13763            if !action.stop_at_newlines {
13764                this.change_selections(Default::default(), window, cx, |s| {
13765                    s.move_with(|_, sel| {
13766                        if sel.is_empty() {
13767                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13768                        }
13769                    });
13770                });
13771            }
13772            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13773            let item = this.cut_common(false, window, cx);
13774            cx.write_to_clipboard(item);
13775        });
13776    }
13777
13778    pub fn move_to_start_of_paragraph(
13779        &mut self,
13780        _: &MoveToStartOfParagraph,
13781        window: &mut Window,
13782        cx: &mut Context<Self>,
13783    ) {
13784        if matches!(self.mode, EditorMode::SingleLine) {
13785            cx.propagate();
13786            return;
13787        }
13788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13789        self.change_selections(Default::default(), window, cx, |s| {
13790            s.move_with(|map, selection| {
13791                selection.collapse_to(
13792                    movement::start_of_paragraph(map, selection.head(), 1),
13793                    SelectionGoal::None,
13794                )
13795            });
13796        })
13797    }
13798
13799    pub fn move_to_end_of_paragraph(
13800        &mut self,
13801        _: &MoveToEndOfParagraph,
13802        window: &mut Window,
13803        cx: &mut Context<Self>,
13804    ) {
13805        if matches!(self.mode, EditorMode::SingleLine) {
13806            cx.propagate();
13807            return;
13808        }
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13810        self.change_selections(Default::default(), window, cx, |s| {
13811            s.move_with(|map, selection| {
13812                selection.collapse_to(
13813                    movement::end_of_paragraph(map, selection.head(), 1),
13814                    SelectionGoal::None,
13815                )
13816            });
13817        })
13818    }
13819
13820    pub fn select_to_start_of_paragraph(
13821        &mut self,
13822        _: &SelectToStartOfParagraph,
13823        window: &mut Window,
13824        cx: &mut Context<Self>,
13825    ) {
13826        if matches!(self.mode, EditorMode::SingleLine) {
13827            cx.propagate();
13828            return;
13829        }
13830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13831        self.change_selections(Default::default(), window, cx, |s| {
13832            s.move_heads_with(|map, head, _| {
13833                (
13834                    movement::start_of_paragraph(map, head, 1),
13835                    SelectionGoal::None,
13836                )
13837            });
13838        })
13839    }
13840
13841    pub fn select_to_end_of_paragraph(
13842        &mut self,
13843        _: &SelectToEndOfParagraph,
13844        window: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        if matches!(self.mode, EditorMode::SingleLine) {
13848            cx.propagate();
13849            return;
13850        }
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13852        self.change_selections(Default::default(), window, cx, |s| {
13853            s.move_heads_with(|map, head, _| {
13854                (
13855                    movement::end_of_paragraph(map, head, 1),
13856                    SelectionGoal::None,
13857                )
13858            });
13859        })
13860    }
13861
13862    pub fn move_to_start_of_excerpt(
13863        &mut self,
13864        _: &MoveToStartOfExcerpt,
13865        window: &mut Window,
13866        cx: &mut Context<Self>,
13867    ) {
13868        if matches!(self.mode, EditorMode::SingleLine) {
13869            cx.propagate();
13870            return;
13871        }
13872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13873        self.change_selections(Default::default(), window, cx, |s| {
13874            s.move_with(|map, selection| {
13875                selection.collapse_to(
13876                    movement::start_of_excerpt(
13877                        map,
13878                        selection.head(),
13879                        workspace::searchable::Direction::Prev,
13880                    ),
13881                    SelectionGoal::None,
13882                )
13883            });
13884        })
13885    }
13886
13887    pub fn move_to_start_of_next_excerpt(
13888        &mut self,
13889        _: &MoveToStartOfNextExcerpt,
13890        window: &mut Window,
13891        cx: &mut Context<Self>,
13892    ) {
13893        if matches!(self.mode, EditorMode::SingleLine) {
13894            cx.propagate();
13895            return;
13896        }
13897
13898        self.change_selections(Default::default(), window, cx, |s| {
13899            s.move_with(|map, selection| {
13900                selection.collapse_to(
13901                    movement::start_of_excerpt(
13902                        map,
13903                        selection.head(),
13904                        workspace::searchable::Direction::Next,
13905                    ),
13906                    SelectionGoal::None,
13907                )
13908            });
13909        })
13910    }
13911
13912    pub fn move_to_end_of_excerpt(
13913        &mut self,
13914        _: &MoveToEndOfExcerpt,
13915        window: &mut Window,
13916        cx: &mut Context<Self>,
13917    ) {
13918        if matches!(self.mode, EditorMode::SingleLine) {
13919            cx.propagate();
13920            return;
13921        }
13922        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13923        self.change_selections(Default::default(), window, cx, |s| {
13924            s.move_with(|map, selection| {
13925                selection.collapse_to(
13926                    movement::end_of_excerpt(
13927                        map,
13928                        selection.head(),
13929                        workspace::searchable::Direction::Next,
13930                    ),
13931                    SelectionGoal::None,
13932                )
13933            });
13934        })
13935    }
13936
13937    pub fn move_to_end_of_previous_excerpt(
13938        &mut self,
13939        _: &MoveToEndOfPreviousExcerpt,
13940        window: &mut Window,
13941        cx: &mut Context<Self>,
13942    ) {
13943        if matches!(self.mode, EditorMode::SingleLine) {
13944            cx.propagate();
13945            return;
13946        }
13947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13948        self.change_selections(Default::default(), window, cx, |s| {
13949            s.move_with(|map, selection| {
13950                selection.collapse_to(
13951                    movement::end_of_excerpt(
13952                        map,
13953                        selection.head(),
13954                        workspace::searchable::Direction::Prev,
13955                    ),
13956                    SelectionGoal::None,
13957                )
13958            });
13959        })
13960    }
13961
13962    pub fn select_to_start_of_excerpt(
13963        &mut self,
13964        _: &SelectToStartOfExcerpt,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        if matches!(self.mode, EditorMode::SingleLine) {
13969            cx.propagate();
13970            return;
13971        }
13972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13973        self.change_selections(Default::default(), window, cx, |s| {
13974            s.move_heads_with(|map, head, _| {
13975                (
13976                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13977                    SelectionGoal::None,
13978                )
13979            });
13980        })
13981    }
13982
13983    pub fn select_to_start_of_next_excerpt(
13984        &mut self,
13985        _: &SelectToStartOfNextExcerpt,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        if matches!(self.mode, EditorMode::SingleLine) {
13990            cx.propagate();
13991            return;
13992        }
13993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13994        self.change_selections(Default::default(), window, cx, |s| {
13995            s.move_heads_with(|map, head, _| {
13996                (
13997                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13998                    SelectionGoal::None,
13999                )
14000            });
14001        })
14002    }
14003
14004    pub fn select_to_end_of_excerpt(
14005        &mut self,
14006        _: &SelectToEndOfExcerpt,
14007        window: &mut Window,
14008        cx: &mut Context<Self>,
14009    ) {
14010        if matches!(self.mode, EditorMode::SingleLine) {
14011            cx.propagate();
14012            return;
14013        }
14014        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14015        self.change_selections(Default::default(), window, cx, |s| {
14016            s.move_heads_with(|map, head, _| {
14017                (
14018                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14019                    SelectionGoal::None,
14020                )
14021            });
14022        })
14023    }
14024
14025    pub fn select_to_end_of_previous_excerpt(
14026        &mut self,
14027        _: &SelectToEndOfPreviousExcerpt,
14028        window: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) {
14031        if matches!(self.mode, EditorMode::SingleLine) {
14032            cx.propagate();
14033            return;
14034        }
14035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14036        self.change_selections(Default::default(), window, cx, |s| {
14037            s.move_heads_with(|map, head, _| {
14038                (
14039                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14040                    SelectionGoal::None,
14041                )
14042            });
14043        })
14044    }
14045
14046    pub fn move_to_beginning(
14047        &mut self,
14048        _: &MoveToBeginning,
14049        window: &mut Window,
14050        cx: &mut Context<Self>,
14051    ) {
14052        if matches!(self.mode, EditorMode::SingleLine) {
14053            cx.propagate();
14054            return;
14055        }
14056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14057        self.change_selections(Default::default(), window, cx, |s| {
14058            s.select_ranges(vec![0..0]);
14059        });
14060    }
14061
14062    pub fn select_to_beginning(
14063        &mut self,
14064        _: &SelectToBeginning,
14065        window: &mut Window,
14066        cx: &mut Context<Self>,
14067    ) {
14068        let mut selection = self.selections.last::<Point>(cx);
14069        selection.set_head(Point::zero(), SelectionGoal::None);
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        self.change_selections(Default::default(), window, cx, |s| {
14072            s.select(vec![selection]);
14073        });
14074    }
14075
14076    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14077        if matches!(self.mode, EditorMode::SingleLine) {
14078            cx.propagate();
14079            return;
14080        }
14081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14082        let cursor = self.buffer.read(cx).read(cx).len();
14083        self.change_selections(Default::default(), window, cx, |s| {
14084            s.select_ranges(vec![cursor..cursor])
14085        });
14086    }
14087
14088    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14089        self.nav_history = nav_history;
14090    }
14091
14092    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14093        self.nav_history.as_ref()
14094    }
14095
14096    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14097        self.push_to_nav_history(
14098            self.selections.newest_anchor().head(),
14099            None,
14100            false,
14101            true,
14102            cx,
14103        );
14104    }
14105
14106    fn push_to_nav_history(
14107        &mut self,
14108        cursor_anchor: Anchor,
14109        new_position: Option<Point>,
14110        is_deactivate: bool,
14111        always: bool,
14112        cx: &mut Context<Self>,
14113    ) {
14114        if let Some(nav_history) = self.nav_history.as_mut() {
14115            let buffer = self.buffer.read(cx).read(cx);
14116            let cursor_position = cursor_anchor.to_point(&buffer);
14117            let scroll_state = self.scroll_manager.anchor();
14118            let scroll_top_row = scroll_state.top_row(&buffer);
14119            drop(buffer);
14120
14121            if let Some(new_position) = new_position {
14122                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14123                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14124                    return;
14125                }
14126            }
14127
14128            nav_history.push(
14129                Some(NavigationData {
14130                    cursor_anchor,
14131                    cursor_position,
14132                    scroll_anchor: scroll_state,
14133                    scroll_top_row,
14134                }),
14135                cx,
14136            );
14137            cx.emit(EditorEvent::PushedToNavHistory {
14138                anchor: cursor_anchor,
14139                is_deactivate,
14140            })
14141        }
14142    }
14143
14144    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14146        let buffer = self.buffer.read(cx).snapshot(cx);
14147        let mut selection = self.selections.first::<usize>(cx);
14148        selection.set_head(buffer.len(), SelectionGoal::None);
14149        self.change_selections(Default::default(), window, cx, |s| {
14150            s.select(vec![selection]);
14151        });
14152    }
14153
14154    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14156        let end = self.buffer.read(cx).read(cx).len();
14157        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14158            s.select_ranges(vec![0..end]);
14159        });
14160    }
14161
14162    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14165        let mut selections = self.selections.all::<Point>(cx);
14166        let max_point = display_map.buffer_snapshot().max_point();
14167        for selection in &mut selections {
14168            let rows = selection.spanned_rows(true, &display_map);
14169            selection.start = Point::new(rows.start.0, 0);
14170            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14171            selection.reversed = false;
14172        }
14173        self.change_selections(Default::default(), window, cx, |s| {
14174            s.select(selections);
14175        });
14176    }
14177
14178    pub fn split_selection_into_lines(
14179        &mut self,
14180        action: &SplitSelectionIntoLines,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        let selections = self
14185            .selections
14186            .all::<Point>(cx)
14187            .into_iter()
14188            .map(|selection| selection.start..selection.end)
14189            .collect::<Vec<_>>();
14190        self.unfold_ranges(&selections, true, true, cx);
14191
14192        let mut new_selection_ranges = Vec::new();
14193        {
14194            let buffer = self.buffer.read(cx).read(cx);
14195            for selection in selections {
14196                for row in selection.start.row..selection.end.row {
14197                    let line_start = Point::new(row, 0);
14198                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14199
14200                    if action.keep_selections {
14201                        // Keep the selection range for each line
14202                        let selection_start = if row == selection.start.row {
14203                            selection.start
14204                        } else {
14205                            line_start
14206                        };
14207                        new_selection_ranges.push(selection_start..line_end);
14208                    } else {
14209                        // Collapse to cursor at end of line
14210                        new_selection_ranges.push(line_end..line_end);
14211                    }
14212                }
14213
14214                let is_multiline_selection = selection.start.row != selection.end.row;
14215                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14216                // so this action feels more ergonomic when paired with other selection operations
14217                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14218                if !should_skip_last {
14219                    if action.keep_selections {
14220                        if is_multiline_selection {
14221                            let line_start = Point::new(selection.end.row, 0);
14222                            new_selection_ranges.push(line_start..selection.end);
14223                        } else {
14224                            new_selection_ranges.push(selection.start..selection.end);
14225                        }
14226                    } else {
14227                        new_selection_ranges.push(selection.end..selection.end);
14228                    }
14229                }
14230            }
14231        }
14232        self.change_selections(Default::default(), window, cx, |s| {
14233            s.select_ranges(new_selection_ranges);
14234        });
14235    }
14236
14237    pub fn add_selection_above(
14238        &mut self,
14239        _: &AddSelectionAbove,
14240        window: &mut Window,
14241        cx: &mut Context<Self>,
14242    ) {
14243        self.add_selection(true, window, cx);
14244    }
14245
14246    pub fn add_selection_below(
14247        &mut self,
14248        _: &AddSelectionBelow,
14249        window: &mut Window,
14250        cx: &mut Context<Self>,
14251    ) {
14252        self.add_selection(false, window, cx);
14253    }
14254
14255    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14257
14258        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14259        let all_selections = self.selections.all::<Point>(cx);
14260        let text_layout_details = self.text_layout_details(window);
14261
14262        let (mut columnar_selections, new_selections_to_columnarize) = {
14263            if let Some(state) = self.add_selections_state.as_ref() {
14264                let columnar_selection_ids: HashSet<_> = state
14265                    .groups
14266                    .iter()
14267                    .flat_map(|group| group.stack.iter())
14268                    .copied()
14269                    .collect();
14270
14271                all_selections
14272                    .into_iter()
14273                    .partition(|s| columnar_selection_ids.contains(&s.id))
14274            } else {
14275                (Vec::new(), all_selections)
14276            }
14277        };
14278
14279        let mut state = self
14280            .add_selections_state
14281            .take()
14282            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14283
14284        for selection in new_selections_to_columnarize {
14285            let range = selection.display_range(&display_map).sorted();
14286            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14287            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14288            let positions = start_x.min(end_x)..start_x.max(end_x);
14289            let mut stack = Vec::new();
14290            for row in range.start.row().0..=range.end.row().0 {
14291                if let Some(selection) = self.selections.build_columnar_selection(
14292                    &display_map,
14293                    DisplayRow(row),
14294                    &positions,
14295                    selection.reversed,
14296                    &text_layout_details,
14297                ) {
14298                    stack.push(selection.id);
14299                    columnar_selections.push(selection);
14300                }
14301            }
14302            if !stack.is_empty() {
14303                if above {
14304                    stack.reverse();
14305                }
14306                state.groups.push(AddSelectionsGroup { above, stack });
14307            }
14308        }
14309
14310        let mut final_selections = Vec::new();
14311        let end_row = if above {
14312            DisplayRow(0)
14313        } else {
14314            display_map.max_point().row()
14315        };
14316
14317        let mut last_added_item_per_group = HashMap::default();
14318        for group in state.groups.iter_mut() {
14319            if let Some(last_id) = group.stack.last() {
14320                last_added_item_per_group.insert(*last_id, group);
14321            }
14322        }
14323
14324        for selection in columnar_selections {
14325            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14326                if above == group.above {
14327                    let range = selection.display_range(&display_map).sorted();
14328                    debug_assert_eq!(range.start.row(), range.end.row());
14329                    let mut row = range.start.row();
14330                    let positions =
14331                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14332                            Pixels::from(start)..Pixels::from(end)
14333                        } else {
14334                            let start_x =
14335                                display_map.x_for_display_point(range.start, &text_layout_details);
14336                            let end_x =
14337                                display_map.x_for_display_point(range.end, &text_layout_details);
14338                            start_x.min(end_x)..start_x.max(end_x)
14339                        };
14340
14341                    let mut maybe_new_selection = None;
14342                    while row != end_row {
14343                        if above {
14344                            row.0 -= 1;
14345                        } else {
14346                            row.0 += 1;
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| {
16962            match multibuffer_selection_mode {
16963                MultibufferSelectionMode::First => {
16964                    if let Some(first_range) = ranges.first() {
16965                        editor.change_selections(
16966                            SelectionEffects::no_scroll(),
16967                            window,
16968                            cx,
16969                            |selections| {
16970                                selections.clear_disjoint();
16971                                selections
16972                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16973                            },
16974                        );
16975                    }
16976                    editor.highlight_background::<Self>(
16977                        &ranges,
16978                        |theme| theme.colors().editor_highlighted_line_background,
16979                        cx,
16980                    );
16981                }
16982                MultibufferSelectionMode::All => {
16983                    editor.change_selections(
16984                        SelectionEffects::no_scroll(),
16985                        window,
16986                        cx,
16987                        |selections| {
16988                            selections.clear_disjoint();
16989                            selections.select_anchor_ranges(ranges);
16990                        },
16991                    );
16992                }
16993            }
16994            editor.register_buffers_with_language_servers(cx);
16995        });
16996
16997        let item = Box::new(editor);
16998        let item_id = item.item_id();
16999
17000        if split {
17001            let pane = workspace.adjacent_pane(window, cx);
17002            workspace.add_item(pane, item, None, true, true, window, cx);
17003        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17004            let (preview_item_id, preview_item_idx) =
17005                workspace.active_pane().read_with(cx, |pane, _| {
17006                    (pane.preview_item_id(), pane.preview_item_idx())
17007                });
17008
17009            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17010
17011            if let Some(preview_item_id) = preview_item_id {
17012                workspace.active_pane().update(cx, |pane, cx| {
17013                    pane.remove_item(preview_item_id, false, false, window, cx);
17014                });
17015            }
17016        } else {
17017            workspace.add_item_to_active_pane(item, None, true, window, cx);
17018        }
17019        workspace.active_pane().update(cx, |pane, cx| {
17020            pane.set_preview_item_id(Some(item_id), cx);
17021        });
17022    }
17023
17024    pub fn rename(
17025        &mut self,
17026        _: &Rename,
17027        window: &mut Window,
17028        cx: &mut Context<Self>,
17029    ) -> Option<Task<Result<()>>> {
17030        use language::ToOffset as _;
17031
17032        let provider = self.semantics_provider.clone()?;
17033        let selection = self.selections.newest_anchor().clone();
17034        let (cursor_buffer, cursor_buffer_position) = self
17035            .buffer
17036            .read(cx)
17037            .text_anchor_for_position(selection.head(), cx)?;
17038        let (tail_buffer, cursor_buffer_position_end) = self
17039            .buffer
17040            .read(cx)
17041            .text_anchor_for_position(selection.tail(), cx)?;
17042        if tail_buffer != cursor_buffer {
17043            return None;
17044        }
17045
17046        let snapshot = cursor_buffer.read(cx).snapshot();
17047        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17048        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17049        let prepare_rename = provider
17050            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17051            .unwrap_or_else(|| Task::ready(Ok(None)));
17052        drop(snapshot);
17053
17054        Some(cx.spawn_in(window, async move |this, cx| {
17055            let rename_range = if let Some(range) = prepare_rename.await? {
17056                Some(range)
17057            } else {
17058                this.update(cx, |this, cx| {
17059                    let buffer = this.buffer.read(cx).snapshot(cx);
17060                    let mut buffer_highlights = this
17061                        .document_highlights_for_position(selection.head(), &buffer)
17062                        .filter(|highlight| {
17063                            highlight.start.excerpt_id == selection.head().excerpt_id
17064                                && highlight.end.excerpt_id == selection.head().excerpt_id
17065                        });
17066                    buffer_highlights
17067                        .next()
17068                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17069                })?
17070            };
17071            if let Some(rename_range) = rename_range {
17072                this.update_in(cx, |this, window, cx| {
17073                    let snapshot = cursor_buffer.read(cx).snapshot();
17074                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17075                    let cursor_offset_in_rename_range =
17076                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17077                    let cursor_offset_in_rename_range_end =
17078                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17079
17080                    this.take_rename(false, window, cx);
17081                    let buffer = this.buffer.read(cx).read(cx);
17082                    let cursor_offset = selection.head().to_offset(&buffer);
17083                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17084                    let rename_end = rename_start + rename_buffer_range.len();
17085                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17086                    let mut old_highlight_id = None;
17087                    let old_name: Arc<str> = buffer
17088                        .chunks(rename_start..rename_end, true)
17089                        .map(|chunk| {
17090                            if old_highlight_id.is_none() {
17091                                old_highlight_id = chunk.syntax_highlight_id;
17092                            }
17093                            chunk.text
17094                        })
17095                        .collect::<String>()
17096                        .into();
17097
17098                    drop(buffer);
17099
17100                    // Position the selection in the rename editor so that it matches the current selection.
17101                    this.show_local_selections = false;
17102                    let rename_editor = cx.new(|cx| {
17103                        let mut editor = Editor::single_line(window, cx);
17104                        editor.buffer.update(cx, |buffer, cx| {
17105                            buffer.edit([(0..0, old_name.clone())], None, cx)
17106                        });
17107                        let rename_selection_range = match cursor_offset_in_rename_range
17108                            .cmp(&cursor_offset_in_rename_range_end)
17109                        {
17110                            Ordering::Equal => {
17111                                editor.select_all(&SelectAll, window, cx);
17112                                return editor;
17113                            }
17114                            Ordering::Less => {
17115                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17116                            }
17117                            Ordering::Greater => {
17118                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17119                            }
17120                        };
17121                        if rename_selection_range.end > old_name.len() {
17122                            editor.select_all(&SelectAll, window, cx);
17123                        } else {
17124                            editor.change_selections(Default::default(), window, cx, |s| {
17125                                s.select_ranges([rename_selection_range]);
17126                            });
17127                        }
17128                        editor
17129                    });
17130                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17131                        if e == &EditorEvent::Focused {
17132                            cx.emit(EditorEvent::FocusedIn)
17133                        }
17134                    })
17135                    .detach();
17136
17137                    let write_highlights =
17138                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17139                    let read_highlights =
17140                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17141                    let ranges = write_highlights
17142                        .iter()
17143                        .flat_map(|(_, ranges)| ranges.iter())
17144                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17145                        .cloned()
17146                        .collect();
17147
17148                    this.highlight_text::<Rename>(
17149                        ranges,
17150                        HighlightStyle {
17151                            fade_out: Some(0.6),
17152                            ..Default::default()
17153                        },
17154                        cx,
17155                    );
17156                    let rename_focus_handle = rename_editor.focus_handle(cx);
17157                    window.focus(&rename_focus_handle);
17158                    let block_id = this.insert_blocks(
17159                        [BlockProperties {
17160                            style: BlockStyle::Flex,
17161                            placement: BlockPlacement::Below(range.start),
17162                            height: Some(1),
17163                            render: Arc::new({
17164                                let rename_editor = rename_editor.clone();
17165                                move |cx: &mut BlockContext| {
17166                                    let mut text_style = cx.editor_style.text.clone();
17167                                    if let Some(highlight_style) = old_highlight_id
17168                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17169                                    {
17170                                        text_style = text_style.highlight(highlight_style);
17171                                    }
17172                                    div()
17173                                        .block_mouse_except_scroll()
17174                                        .pl(cx.anchor_x)
17175                                        .child(EditorElement::new(
17176                                            &rename_editor,
17177                                            EditorStyle {
17178                                                background: cx.theme().system().transparent,
17179                                                local_player: cx.editor_style.local_player,
17180                                                text: text_style,
17181                                                scrollbar_width: cx.editor_style.scrollbar_width,
17182                                                syntax: cx.editor_style.syntax.clone(),
17183                                                status: cx.editor_style.status.clone(),
17184                                                inlay_hints_style: HighlightStyle {
17185                                                    font_weight: Some(FontWeight::BOLD),
17186                                                    ..make_inlay_hints_style(cx.app)
17187                                                },
17188                                                edit_prediction_styles: make_suggestion_styles(
17189                                                    cx.app,
17190                                                ),
17191                                                ..EditorStyle::default()
17192                                            },
17193                                        ))
17194                                        .into_any_element()
17195                                }
17196                            }),
17197                            priority: 0,
17198                        }],
17199                        Some(Autoscroll::fit()),
17200                        cx,
17201                    )[0];
17202                    this.pending_rename = Some(RenameState {
17203                        range,
17204                        old_name,
17205                        editor: rename_editor,
17206                        block_id,
17207                    });
17208                })?;
17209            }
17210
17211            Ok(())
17212        }))
17213    }
17214
17215    pub fn confirm_rename(
17216        &mut self,
17217        _: &ConfirmRename,
17218        window: &mut Window,
17219        cx: &mut Context<Self>,
17220    ) -> Option<Task<Result<()>>> {
17221        let rename = self.take_rename(false, window, cx)?;
17222        let workspace = self.workspace()?.downgrade();
17223        let (buffer, start) = self
17224            .buffer
17225            .read(cx)
17226            .text_anchor_for_position(rename.range.start, cx)?;
17227        let (end_buffer, _) = self
17228            .buffer
17229            .read(cx)
17230            .text_anchor_for_position(rename.range.end, cx)?;
17231        if buffer != end_buffer {
17232            return None;
17233        }
17234
17235        let old_name = rename.old_name;
17236        let new_name = rename.editor.read(cx).text(cx);
17237
17238        let rename = self.semantics_provider.as_ref()?.perform_rename(
17239            &buffer,
17240            start,
17241            new_name.clone(),
17242            cx,
17243        )?;
17244
17245        Some(cx.spawn_in(window, async move |editor, cx| {
17246            let project_transaction = rename.await?;
17247            Self::open_project_transaction(
17248                &editor,
17249                workspace,
17250                project_transaction,
17251                format!("Rename: {}{}", old_name, new_name),
17252                cx,
17253            )
17254            .await?;
17255
17256            editor.update(cx, |editor, cx| {
17257                editor.refresh_document_highlights(cx);
17258            })?;
17259            Ok(())
17260        }))
17261    }
17262
17263    fn take_rename(
17264        &mut self,
17265        moving_cursor: bool,
17266        window: &mut Window,
17267        cx: &mut Context<Self>,
17268    ) -> Option<RenameState> {
17269        let rename = self.pending_rename.take()?;
17270        if rename.editor.focus_handle(cx).is_focused(window) {
17271            window.focus(&self.focus_handle);
17272        }
17273
17274        self.remove_blocks(
17275            [rename.block_id].into_iter().collect(),
17276            Some(Autoscroll::fit()),
17277            cx,
17278        );
17279        self.clear_highlights::<Rename>(cx);
17280        self.show_local_selections = true;
17281
17282        if moving_cursor {
17283            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17284                editor.selections.newest::<usize>(cx).head()
17285            });
17286
17287            // Update the selection to match the position of the selection inside
17288            // the rename editor.
17289            let snapshot = self.buffer.read(cx).read(cx);
17290            let rename_range = rename.range.to_offset(&snapshot);
17291            let cursor_in_editor = snapshot
17292                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17293                .min(rename_range.end);
17294            drop(snapshot);
17295
17296            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17297                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17298            });
17299        } else {
17300            self.refresh_document_highlights(cx);
17301        }
17302
17303        Some(rename)
17304    }
17305
17306    pub fn pending_rename(&self) -> Option<&RenameState> {
17307        self.pending_rename.as_ref()
17308    }
17309
17310    fn format(
17311        &mut self,
17312        _: &Format,
17313        window: &mut Window,
17314        cx: &mut Context<Self>,
17315    ) -> Option<Task<Result<()>>> {
17316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17317
17318        let project = match &self.project {
17319            Some(project) => project.clone(),
17320            None => return None,
17321        };
17322
17323        Some(self.perform_format(
17324            project,
17325            FormatTrigger::Manual,
17326            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17327            window,
17328            cx,
17329        ))
17330    }
17331
17332    fn format_selections(
17333        &mut self,
17334        _: &FormatSelections,
17335        window: &mut Window,
17336        cx: &mut Context<Self>,
17337    ) -> Option<Task<Result<()>>> {
17338        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17339
17340        let project = match &self.project {
17341            Some(project) => project.clone(),
17342            None => return None,
17343        };
17344
17345        let ranges = self
17346            .selections
17347            .all_adjusted(cx)
17348            .into_iter()
17349            .map(|selection| selection.range())
17350            .collect_vec();
17351
17352        Some(self.perform_format(
17353            project,
17354            FormatTrigger::Manual,
17355            FormatTarget::Ranges(ranges),
17356            window,
17357            cx,
17358        ))
17359    }
17360
17361    fn perform_format(
17362        &mut self,
17363        project: Entity<Project>,
17364        trigger: FormatTrigger,
17365        target: FormatTarget,
17366        window: &mut Window,
17367        cx: &mut Context<Self>,
17368    ) -> Task<Result<()>> {
17369        let buffer = self.buffer.clone();
17370        let (buffers, target) = match target {
17371            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17372            FormatTarget::Ranges(selection_ranges) => {
17373                let multi_buffer = buffer.read(cx);
17374                let snapshot = multi_buffer.read(cx);
17375                let mut buffers = HashSet::default();
17376                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17377                    BTreeMap::new();
17378                for selection_range in selection_ranges {
17379                    for (buffer, buffer_range, _) in
17380                        snapshot.range_to_buffer_ranges(selection_range)
17381                    {
17382                        let buffer_id = buffer.remote_id();
17383                        let start = buffer.anchor_before(buffer_range.start);
17384                        let end = buffer.anchor_after(buffer_range.end);
17385                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17386                        buffer_id_to_ranges
17387                            .entry(buffer_id)
17388                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17389                            .or_insert_with(|| vec![start..end]);
17390                    }
17391                }
17392                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17393            }
17394        };
17395
17396        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17397        let selections_prev = transaction_id_prev
17398            .and_then(|transaction_id_prev| {
17399                // default to selections as they were after the last edit, if we have them,
17400                // instead of how they are now.
17401                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17402                // will take you back to where you made the last edit, instead of staying where you scrolled
17403                self.selection_history
17404                    .transaction(transaction_id_prev)
17405                    .map(|t| t.0.clone())
17406            })
17407            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17408
17409        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17410        let format = project.update(cx, |project, cx| {
17411            project.format(buffers, target, true, trigger, cx)
17412        });
17413
17414        cx.spawn_in(window, async move |editor, cx| {
17415            let transaction = futures::select_biased! {
17416                transaction = format.log_err().fuse() => transaction,
17417                () = timeout => {
17418                    log::warn!("timed out waiting for formatting");
17419                    None
17420                }
17421            };
17422
17423            buffer
17424                .update(cx, |buffer, cx| {
17425                    if let Some(transaction) = transaction
17426                        && !buffer.is_singleton()
17427                    {
17428                        buffer.push_transaction(&transaction.0, cx);
17429                    }
17430                    cx.notify();
17431                })
17432                .ok();
17433
17434            if let Some(transaction_id_now) =
17435                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17436            {
17437                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17438                if has_new_transaction {
17439                    _ = editor.update(cx, |editor, _| {
17440                        editor
17441                            .selection_history
17442                            .insert_transaction(transaction_id_now, selections_prev);
17443                    });
17444                }
17445            }
17446
17447            Ok(())
17448        })
17449    }
17450
17451    fn organize_imports(
17452        &mut self,
17453        _: &OrganizeImports,
17454        window: &mut Window,
17455        cx: &mut Context<Self>,
17456    ) -> Option<Task<Result<()>>> {
17457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17458        let project = match &self.project {
17459            Some(project) => project.clone(),
17460            None => return None,
17461        };
17462        Some(self.perform_code_action_kind(
17463            project,
17464            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17465            window,
17466            cx,
17467        ))
17468    }
17469
17470    fn perform_code_action_kind(
17471        &mut self,
17472        project: Entity<Project>,
17473        kind: CodeActionKind,
17474        window: &mut Window,
17475        cx: &mut Context<Self>,
17476    ) -> Task<Result<()>> {
17477        let buffer = self.buffer.clone();
17478        let buffers = buffer.read(cx).all_buffers();
17479        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17480        let apply_action = project.update(cx, |project, cx| {
17481            project.apply_code_action_kind(buffers, kind, true, cx)
17482        });
17483        cx.spawn_in(window, async move |_, cx| {
17484            let transaction = futures::select_biased! {
17485                () = timeout => {
17486                    log::warn!("timed out waiting for executing code action");
17487                    None
17488                }
17489                transaction = apply_action.log_err().fuse() => transaction,
17490            };
17491            buffer
17492                .update(cx, |buffer, cx| {
17493                    // check if we need this
17494                    if let Some(transaction) = transaction
17495                        && !buffer.is_singleton()
17496                    {
17497                        buffer.push_transaction(&transaction.0, cx);
17498                    }
17499                    cx.notify();
17500                })
17501                .ok();
17502            Ok(())
17503        })
17504    }
17505
17506    pub fn restart_language_server(
17507        &mut self,
17508        _: &RestartLanguageServer,
17509        _: &mut Window,
17510        cx: &mut Context<Self>,
17511    ) {
17512        if let Some(project) = self.project.clone() {
17513            self.buffer.update(cx, |multi_buffer, cx| {
17514                project.update(cx, |project, cx| {
17515                    project.restart_language_servers_for_buffers(
17516                        multi_buffer.all_buffers().into_iter().collect(),
17517                        HashSet::default(),
17518                        cx,
17519                    );
17520                });
17521            })
17522        }
17523    }
17524
17525    pub fn stop_language_server(
17526        &mut self,
17527        _: &StopLanguageServer,
17528        _: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        if let Some(project) = self.project.clone() {
17532            self.buffer.update(cx, |multi_buffer, cx| {
17533                project.update(cx, |project, cx| {
17534                    project.stop_language_servers_for_buffers(
17535                        multi_buffer.all_buffers().into_iter().collect(),
17536                        HashSet::default(),
17537                        cx,
17538                    );
17539                    cx.emit(project::Event::RefreshInlayHints);
17540                });
17541            });
17542        }
17543    }
17544
17545    fn cancel_language_server_work(
17546        workspace: &mut Workspace,
17547        _: &actions::CancelLanguageServerWork,
17548        _: &mut Window,
17549        cx: &mut Context<Workspace>,
17550    ) {
17551        let project = workspace.project();
17552        let buffers = workspace
17553            .active_item(cx)
17554            .and_then(|item| item.act_as::<Editor>(cx))
17555            .map_or(HashSet::default(), |editor| {
17556                editor.read(cx).buffer.read(cx).all_buffers()
17557            });
17558        project.update(cx, |project, cx| {
17559            project.cancel_language_server_work_for_buffers(buffers, cx);
17560        });
17561    }
17562
17563    fn show_character_palette(
17564        &mut self,
17565        _: &ShowCharacterPalette,
17566        window: &mut Window,
17567        _: &mut Context<Self>,
17568    ) {
17569        window.show_character_palette();
17570    }
17571
17572    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17573        if !self.diagnostics_enabled() {
17574            return;
17575        }
17576
17577        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17578            let buffer = self.buffer.read(cx).snapshot(cx);
17579            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17580            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17581            let is_valid = buffer
17582                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17583                .any(|entry| {
17584                    entry.diagnostic.is_primary
17585                        && !entry.range.is_empty()
17586                        && entry.range.start == primary_range_start
17587                        && entry.diagnostic.message == active_diagnostics.active_message
17588                });
17589
17590            if !is_valid {
17591                self.dismiss_diagnostics(cx);
17592            }
17593        }
17594    }
17595
17596    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17597        match &self.active_diagnostics {
17598            ActiveDiagnostic::Group(group) => Some(group),
17599            _ => None,
17600        }
17601    }
17602
17603    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17604        if !self.diagnostics_enabled() {
17605            return;
17606        }
17607        self.dismiss_diagnostics(cx);
17608        self.active_diagnostics = ActiveDiagnostic::All;
17609    }
17610
17611    fn activate_diagnostics(
17612        &mut self,
17613        buffer_id: BufferId,
17614        diagnostic: DiagnosticEntryRef<'_, usize>,
17615        window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17619            return;
17620        }
17621        self.dismiss_diagnostics(cx);
17622        let snapshot = self.snapshot(window, cx);
17623        let buffer = self.buffer.read(cx).snapshot(cx);
17624        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17625            return;
17626        };
17627
17628        let diagnostic_group = buffer
17629            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17630            .collect::<Vec<_>>();
17631
17632        let blocks =
17633            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17634
17635        let blocks = self.display_map.update(cx, |display_map, cx| {
17636            display_map.insert_blocks(blocks, cx).into_iter().collect()
17637        });
17638        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17639            active_range: buffer.anchor_before(diagnostic.range.start)
17640                ..buffer.anchor_after(diagnostic.range.end),
17641            active_message: diagnostic.diagnostic.message.clone(),
17642            group_id: diagnostic.diagnostic.group_id,
17643            blocks,
17644        });
17645        cx.notify();
17646    }
17647
17648    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17649        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17650            return;
17651        };
17652
17653        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17654        if let ActiveDiagnostic::Group(group) = prev {
17655            self.display_map.update(cx, |display_map, cx| {
17656                display_map.remove_blocks(group.blocks, cx);
17657            });
17658            cx.notify();
17659        }
17660    }
17661
17662    /// Disable inline diagnostics rendering for this editor.
17663    pub fn disable_inline_diagnostics(&mut self) {
17664        self.inline_diagnostics_enabled = false;
17665        self.inline_diagnostics_update = Task::ready(());
17666        self.inline_diagnostics.clear();
17667    }
17668
17669    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17670        self.diagnostics_enabled = false;
17671        self.dismiss_diagnostics(cx);
17672        self.inline_diagnostics_update = Task::ready(());
17673        self.inline_diagnostics.clear();
17674    }
17675
17676    pub fn disable_word_completions(&mut self) {
17677        self.word_completions_enabled = false;
17678    }
17679
17680    pub fn diagnostics_enabled(&self) -> bool {
17681        self.diagnostics_enabled && self.mode.is_full()
17682    }
17683
17684    pub fn inline_diagnostics_enabled(&self) -> bool {
17685        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17686    }
17687
17688    pub fn show_inline_diagnostics(&self) -> bool {
17689        self.show_inline_diagnostics
17690    }
17691
17692    pub fn toggle_inline_diagnostics(
17693        &mut self,
17694        _: &ToggleInlineDiagnostics,
17695        window: &mut Window,
17696        cx: &mut Context<Editor>,
17697    ) {
17698        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17699        self.refresh_inline_diagnostics(false, window, cx);
17700    }
17701
17702    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17703        self.diagnostics_max_severity = severity;
17704        self.display_map.update(cx, |display_map, _| {
17705            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17706        });
17707    }
17708
17709    pub fn toggle_diagnostics(
17710        &mut self,
17711        _: &ToggleDiagnostics,
17712        window: &mut Window,
17713        cx: &mut Context<Editor>,
17714    ) {
17715        if !self.diagnostics_enabled() {
17716            return;
17717        }
17718
17719        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17720            EditorSettings::get_global(cx)
17721                .diagnostics_max_severity
17722                .filter(|severity| severity != &DiagnosticSeverity::Off)
17723                .unwrap_or(DiagnosticSeverity::Hint)
17724        } else {
17725            DiagnosticSeverity::Off
17726        };
17727        self.set_max_diagnostics_severity(new_severity, cx);
17728        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17729            self.active_diagnostics = ActiveDiagnostic::None;
17730            self.inline_diagnostics_update = Task::ready(());
17731            self.inline_diagnostics.clear();
17732        } else {
17733            self.refresh_inline_diagnostics(false, window, cx);
17734        }
17735
17736        cx.notify();
17737    }
17738
17739    pub fn toggle_minimap(
17740        &mut self,
17741        _: &ToggleMinimap,
17742        window: &mut Window,
17743        cx: &mut Context<Editor>,
17744    ) {
17745        if self.supports_minimap(cx) {
17746            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17747        }
17748    }
17749
17750    fn refresh_inline_diagnostics(
17751        &mut self,
17752        debounce: bool,
17753        window: &mut Window,
17754        cx: &mut Context<Self>,
17755    ) {
17756        let max_severity = ProjectSettings::get_global(cx)
17757            .diagnostics
17758            .inline
17759            .max_severity
17760            .unwrap_or(self.diagnostics_max_severity);
17761
17762        if !self.inline_diagnostics_enabled()
17763            || !self.show_inline_diagnostics
17764            || max_severity == DiagnosticSeverity::Off
17765        {
17766            self.inline_diagnostics_update = Task::ready(());
17767            self.inline_diagnostics.clear();
17768            return;
17769        }
17770
17771        let debounce_ms = ProjectSettings::get_global(cx)
17772            .diagnostics
17773            .inline
17774            .update_debounce_ms;
17775        let debounce = if debounce && debounce_ms > 0 {
17776            Some(Duration::from_millis(debounce_ms))
17777        } else {
17778            None
17779        };
17780        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17781            if let Some(debounce) = debounce {
17782                cx.background_executor().timer(debounce).await;
17783            }
17784            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17785                editor
17786                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17787                    .ok()
17788            }) else {
17789                return;
17790            };
17791
17792            let new_inline_diagnostics = cx
17793                .background_spawn(async move {
17794                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17795                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17796                        let message = diagnostic_entry
17797                            .diagnostic
17798                            .message
17799                            .split_once('\n')
17800                            .map(|(line, _)| line)
17801                            .map(SharedString::new)
17802                            .unwrap_or_else(|| {
17803                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17804                            });
17805                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17806                        let (Ok(i) | Err(i)) = inline_diagnostics
17807                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17808                        inline_diagnostics.insert(
17809                            i,
17810                            (
17811                                start_anchor,
17812                                InlineDiagnostic {
17813                                    message,
17814                                    group_id: diagnostic_entry.diagnostic.group_id,
17815                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17816                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17817                                    severity: diagnostic_entry.diagnostic.severity,
17818                                },
17819                            ),
17820                        );
17821                    }
17822                    inline_diagnostics
17823                })
17824                .await;
17825
17826            editor
17827                .update(cx, |editor, cx| {
17828                    editor.inline_diagnostics = new_inline_diagnostics;
17829                    cx.notify();
17830                })
17831                .ok();
17832        });
17833    }
17834
17835    fn pull_diagnostics(
17836        &mut self,
17837        buffer_id: Option<BufferId>,
17838        window: &Window,
17839        cx: &mut Context<Self>,
17840    ) -> Option<()> {
17841        if !self.mode().is_full() {
17842            return None;
17843        }
17844        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17845            .diagnostics
17846            .lsp_pull_diagnostics;
17847        if !pull_diagnostics_settings.enabled {
17848            return None;
17849        }
17850        let project = self.project()?.downgrade();
17851        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17852        let mut buffers = self.buffer.read(cx).all_buffers();
17853        if let Some(buffer_id) = buffer_id {
17854            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17855        }
17856
17857        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17858            cx.background_executor().timer(debounce).await;
17859
17860            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17861                buffers
17862                    .into_iter()
17863                    .filter_map(|buffer| {
17864                        project
17865                            .update(cx, |project, cx| {
17866                                project.lsp_store().update(cx, |lsp_store, cx| {
17867                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17868                                })
17869                            })
17870                            .ok()
17871                    })
17872                    .collect::<FuturesUnordered<_>>()
17873            }) else {
17874                return;
17875            };
17876
17877            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17878                match pull_task {
17879                    Ok(()) => {
17880                        if editor
17881                            .update_in(cx, |editor, window, cx| {
17882                                editor.update_diagnostics_state(window, cx);
17883                            })
17884                            .is_err()
17885                        {
17886                            return;
17887                        }
17888                    }
17889                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17890                }
17891            }
17892        });
17893
17894        Some(())
17895    }
17896
17897    pub fn set_selections_from_remote(
17898        &mut self,
17899        selections: Vec<Selection<Anchor>>,
17900        pending_selection: Option<Selection<Anchor>>,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) {
17904        let old_cursor_position = self.selections.newest_anchor().head();
17905        self.selections.change_with(cx, |s| {
17906            s.select_anchors(selections);
17907            if let Some(pending_selection) = pending_selection {
17908                s.set_pending(pending_selection, SelectMode::Character);
17909            } else {
17910                s.clear_pending();
17911            }
17912        });
17913        self.selections_did_change(
17914            false,
17915            &old_cursor_position,
17916            SelectionEffects::default(),
17917            window,
17918            cx,
17919        );
17920    }
17921
17922    pub fn transact(
17923        &mut self,
17924        window: &mut Window,
17925        cx: &mut Context<Self>,
17926        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17927    ) -> Option<TransactionId> {
17928        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17929            this.start_transaction_at(Instant::now(), window, cx);
17930            update(this, window, cx);
17931            this.end_transaction_at(Instant::now(), cx)
17932        })
17933    }
17934
17935    pub fn start_transaction_at(
17936        &mut self,
17937        now: Instant,
17938        window: &mut Window,
17939        cx: &mut Context<Self>,
17940    ) -> Option<TransactionId> {
17941        self.end_selection(window, cx);
17942        if let Some(tx_id) = self
17943            .buffer
17944            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17945        {
17946            self.selection_history
17947                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17948            cx.emit(EditorEvent::TransactionBegun {
17949                transaction_id: tx_id,
17950            });
17951            Some(tx_id)
17952        } else {
17953            None
17954        }
17955    }
17956
17957    pub fn end_transaction_at(
17958        &mut self,
17959        now: Instant,
17960        cx: &mut Context<Self>,
17961    ) -> Option<TransactionId> {
17962        if let Some(transaction_id) = self
17963            .buffer
17964            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17965        {
17966            if let Some((_, end_selections)) =
17967                self.selection_history.transaction_mut(transaction_id)
17968            {
17969                *end_selections = Some(self.selections.disjoint_anchors_arc());
17970            } else {
17971                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17972            }
17973
17974            cx.emit(EditorEvent::Edited { transaction_id });
17975            Some(transaction_id)
17976        } else {
17977            None
17978        }
17979    }
17980
17981    pub fn modify_transaction_selection_history(
17982        &mut self,
17983        transaction_id: TransactionId,
17984        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17985    ) -> bool {
17986        self.selection_history
17987            .transaction_mut(transaction_id)
17988            .map(modify)
17989            .is_some()
17990    }
17991
17992    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17993        if self.selection_mark_mode {
17994            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17995                s.move_with(|_, sel| {
17996                    sel.collapse_to(sel.head(), SelectionGoal::None);
17997                });
17998            })
17999        }
18000        self.selection_mark_mode = true;
18001        cx.notify();
18002    }
18003
18004    pub fn swap_selection_ends(
18005        &mut self,
18006        _: &actions::SwapSelectionEnds,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18011            s.move_with(|_, sel| {
18012                if sel.start != sel.end {
18013                    sel.reversed = !sel.reversed
18014                }
18015            });
18016        });
18017        self.request_autoscroll(Autoscroll::newest(), cx);
18018        cx.notify();
18019    }
18020
18021    pub fn toggle_focus(
18022        workspace: &mut Workspace,
18023        _: &actions::ToggleFocus,
18024        window: &mut Window,
18025        cx: &mut Context<Workspace>,
18026    ) {
18027        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18028            return;
18029        };
18030        workspace.activate_item(&item, true, true, window, cx);
18031    }
18032
18033    pub fn toggle_fold(
18034        &mut self,
18035        _: &actions::ToggleFold,
18036        window: &mut Window,
18037        cx: &mut Context<Self>,
18038    ) {
18039        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18040            let selection = self.selections.newest::<Point>(cx);
18041
18042            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18043            let range = if selection.is_empty() {
18044                let point = selection.head().to_display_point(&display_map);
18045                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18046                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18047                    .to_point(&display_map);
18048                start..end
18049            } else {
18050                selection.range()
18051            };
18052            if display_map.folds_in_range(range).next().is_some() {
18053                self.unfold_lines(&Default::default(), window, cx)
18054            } else {
18055                self.fold(&Default::default(), window, cx)
18056            }
18057        } else {
18058            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18059            let buffer_ids: HashSet<_> = self
18060                .selections
18061                .disjoint_anchor_ranges()
18062                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18063                .collect();
18064
18065            let should_unfold = buffer_ids
18066                .iter()
18067                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18068
18069            for buffer_id in buffer_ids {
18070                if should_unfold {
18071                    self.unfold_buffer(buffer_id, cx);
18072                } else {
18073                    self.fold_buffer(buffer_id, cx);
18074                }
18075            }
18076        }
18077    }
18078
18079    pub fn toggle_fold_recursive(
18080        &mut self,
18081        _: &actions::ToggleFoldRecursive,
18082        window: &mut Window,
18083        cx: &mut Context<Self>,
18084    ) {
18085        let selection = self.selections.newest::<Point>(cx);
18086
18087        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18088        let range = if selection.is_empty() {
18089            let point = selection.head().to_display_point(&display_map);
18090            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18091            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18092                .to_point(&display_map);
18093            start..end
18094        } else {
18095            selection.range()
18096        };
18097        if display_map.folds_in_range(range).next().is_some() {
18098            self.unfold_recursive(&Default::default(), window, cx)
18099        } else {
18100            self.fold_recursive(&Default::default(), window, cx)
18101        }
18102    }
18103
18104    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18105        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18106            let mut to_fold = Vec::new();
18107            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18108            let selections = self.selections.all_adjusted(cx);
18109
18110            for selection in selections {
18111                let range = selection.range().sorted();
18112                let buffer_start_row = range.start.row;
18113
18114                if range.start.row != range.end.row {
18115                    let mut found = false;
18116                    let mut row = range.start.row;
18117                    while row <= range.end.row {
18118                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18119                        {
18120                            found = true;
18121                            row = crease.range().end.row + 1;
18122                            to_fold.push(crease);
18123                        } else {
18124                            row += 1
18125                        }
18126                    }
18127                    if found {
18128                        continue;
18129                    }
18130                }
18131
18132                for row in (0..=range.start.row).rev() {
18133                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18134                        && crease.range().end.row >= buffer_start_row
18135                    {
18136                        to_fold.push(crease);
18137                        if row <= range.start.row {
18138                            break;
18139                        }
18140                    }
18141                }
18142            }
18143
18144            self.fold_creases(to_fold, true, window, cx);
18145        } else {
18146            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18147            let buffer_ids = self
18148                .selections
18149                .disjoint_anchor_ranges()
18150                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18151                .collect::<HashSet<_>>();
18152            for buffer_id in buffer_ids {
18153                self.fold_buffer(buffer_id, cx);
18154            }
18155        }
18156    }
18157
18158    pub fn toggle_fold_all(
18159        &mut self,
18160        _: &actions::ToggleFoldAll,
18161        window: &mut Window,
18162        cx: &mut Context<Self>,
18163    ) {
18164        if self.buffer.read(cx).is_singleton() {
18165            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18166            let has_folds = display_map
18167                .folds_in_range(0..display_map.buffer_snapshot().len())
18168                .next()
18169                .is_some();
18170
18171            if has_folds {
18172                self.unfold_all(&actions::UnfoldAll, window, cx);
18173            } else {
18174                self.fold_all(&actions::FoldAll, window, cx);
18175            }
18176        } else {
18177            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18178            let should_unfold = buffer_ids
18179                .iter()
18180                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18181
18182            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18183                editor
18184                    .update_in(cx, |editor, _, cx| {
18185                        for buffer_id in buffer_ids {
18186                            if should_unfold {
18187                                editor.unfold_buffer(buffer_id, cx);
18188                            } else {
18189                                editor.fold_buffer(buffer_id, cx);
18190                            }
18191                        }
18192                    })
18193                    .ok();
18194            });
18195        }
18196    }
18197
18198    fn fold_at_level(
18199        &mut self,
18200        fold_at: &FoldAtLevel,
18201        window: &mut Window,
18202        cx: &mut Context<Self>,
18203    ) {
18204        if !self.buffer.read(cx).is_singleton() {
18205            return;
18206        }
18207
18208        let fold_at_level = fold_at.0;
18209        let snapshot = self.buffer.read(cx).snapshot(cx);
18210        let mut to_fold = Vec::new();
18211        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18212
18213        let row_ranges_to_keep: Vec<Range<u32>> = self
18214            .selections
18215            .all::<Point>(cx)
18216            .into_iter()
18217            .map(|sel| sel.start.row..sel.end.row)
18218            .collect();
18219
18220        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18221            while start_row < end_row {
18222                match self
18223                    .snapshot(window, cx)
18224                    .crease_for_buffer_row(MultiBufferRow(start_row))
18225                {
18226                    Some(crease) => {
18227                        let nested_start_row = crease.range().start.row + 1;
18228                        let nested_end_row = crease.range().end.row;
18229
18230                        if current_level < fold_at_level {
18231                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18232                        } else if current_level == fold_at_level {
18233                            // Fold iff there is no selection completely contained within the fold region
18234                            if !row_ranges_to_keep.iter().any(|selection| {
18235                                selection.end >= nested_start_row
18236                                    && selection.start <= nested_end_row
18237                            }) {
18238                                to_fold.push(crease);
18239                            }
18240                        }
18241
18242                        start_row = nested_end_row + 1;
18243                    }
18244                    None => start_row += 1,
18245                }
18246            }
18247        }
18248
18249        self.fold_creases(to_fold, true, window, cx);
18250    }
18251
18252    pub fn fold_at_level_1(
18253        &mut self,
18254        _: &actions::FoldAtLevel1,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) {
18258        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18259    }
18260
18261    pub fn fold_at_level_2(
18262        &mut self,
18263        _: &actions::FoldAtLevel2,
18264        window: &mut Window,
18265        cx: &mut Context<Self>,
18266    ) {
18267        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18268    }
18269
18270    pub fn fold_at_level_3(
18271        &mut self,
18272        _: &actions::FoldAtLevel3,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275    ) {
18276        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18277    }
18278
18279    pub fn fold_at_level_4(
18280        &mut self,
18281        _: &actions::FoldAtLevel4,
18282        window: &mut Window,
18283        cx: &mut Context<Self>,
18284    ) {
18285        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18286    }
18287
18288    pub fn fold_at_level_5(
18289        &mut self,
18290        _: &actions::FoldAtLevel5,
18291        window: &mut Window,
18292        cx: &mut Context<Self>,
18293    ) {
18294        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18295    }
18296
18297    pub fn fold_at_level_6(
18298        &mut self,
18299        _: &actions::FoldAtLevel6,
18300        window: &mut Window,
18301        cx: &mut Context<Self>,
18302    ) {
18303        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18304    }
18305
18306    pub fn fold_at_level_7(
18307        &mut self,
18308        _: &actions::FoldAtLevel7,
18309        window: &mut Window,
18310        cx: &mut Context<Self>,
18311    ) {
18312        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18313    }
18314
18315    pub fn fold_at_level_8(
18316        &mut self,
18317        _: &actions::FoldAtLevel8,
18318        window: &mut Window,
18319        cx: &mut Context<Self>,
18320    ) {
18321        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18322    }
18323
18324    pub fn fold_at_level_9(
18325        &mut self,
18326        _: &actions::FoldAtLevel9,
18327        window: &mut Window,
18328        cx: &mut Context<Self>,
18329    ) {
18330        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18331    }
18332
18333    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18334        if self.buffer.read(cx).is_singleton() {
18335            let mut fold_ranges = Vec::new();
18336            let snapshot = self.buffer.read(cx).snapshot(cx);
18337
18338            for row in 0..snapshot.max_row().0 {
18339                if let Some(foldable_range) = self
18340                    .snapshot(window, cx)
18341                    .crease_for_buffer_row(MultiBufferRow(row))
18342                {
18343                    fold_ranges.push(foldable_range);
18344                }
18345            }
18346
18347            self.fold_creases(fold_ranges, true, window, cx);
18348        } else {
18349            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18350                editor
18351                    .update_in(cx, |editor, _, cx| {
18352                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18353                            editor.fold_buffer(buffer_id, cx);
18354                        }
18355                    })
18356                    .ok();
18357            });
18358        }
18359    }
18360
18361    pub fn fold_function_bodies(
18362        &mut self,
18363        _: &actions::FoldFunctionBodies,
18364        window: &mut Window,
18365        cx: &mut Context<Self>,
18366    ) {
18367        let snapshot = self.buffer.read(cx).snapshot(cx);
18368
18369        let ranges = snapshot
18370            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18371            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18372            .collect::<Vec<_>>();
18373
18374        let creases = ranges
18375            .into_iter()
18376            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18377            .collect();
18378
18379        self.fold_creases(creases, true, window, cx);
18380    }
18381
18382    pub fn fold_recursive(
18383        &mut self,
18384        _: &actions::FoldRecursive,
18385        window: &mut Window,
18386        cx: &mut Context<Self>,
18387    ) {
18388        let mut to_fold = Vec::new();
18389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18390        let selections = self.selections.all_adjusted(cx);
18391
18392        for selection in selections {
18393            let range = selection.range().sorted();
18394            let buffer_start_row = range.start.row;
18395
18396            if range.start.row != range.end.row {
18397                let mut found = false;
18398                for row in range.start.row..=range.end.row {
18399                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18400                        found = true;
18401                        to_fold.push(crease);
18402                    }
18403                }
18404                if found {
18405                    continue;
18406                }
18407            }
18408
18409            for row in (0..=range.start.row).rev() {
18410                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18411                    if crease.range().end.row >= buffer_start_row {
18412                        to_fold.push(crease);
18413                    } else {
18414                        break;
18415                    }
18416                }
18417            }
18418        }
18419
18420        self.fold_creases(to_fold, true, window, cx);
18421    }
18422
18423    pub fn fold_at(
18424        &mut self,
18425        buffer_row: MultiBufferRow,
18426        window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18430
18431        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18432            let autoscroll = self
18433                .selections
18434                .all::<Point>(cx)
18435                .iter()
18436                .any(|selection| crease.range().overlaps(&selection.range()));
18437
18438            self.fold_creases(vec![crease], autoscroll, window, cx);
18439        }
18440    }
18441
18442    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18443        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18444            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18445            let buffer = display_map.buffer_snapshot();
18446            let selections = self.selections.all::<Point>(cx);
18447            let ranges = selections
18448                .iter()
18449                .map(|s| {
18450                    let range = s.display_range(&display_map).sorted();
18451                    let mut start = range.start.to_point(&display_map);
18452                    let mut end = range.end.to_point(&display_map);
18453                    start.column = 0;
18454                    end.column = buffer.line_len(MultiBufferRow(end.row));
18455                    start..end
18456                })
18457                .collect::<Vec<_>>();
18458
18459            self.unfold_ranges(&ranges, true, true, cx);
18460        } else {
18461            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18462            let buffer_ids = self
18463                .selections
18464                .disjoint_anchor_ranges()
18465                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18466                .collect::<HashSet<_>>();
18467            for buffer_id in buffer_ids {
18468                self.unfold_buffer(buffer_id, cx);
18469            }
18470        }
18471    }
18472
18473    pub fn unfold_recursive(
18474        &mut self,
18475        _: &UnfoldRecursive,
18476        _window: &mut Window,
18477        cx: &mut Context<Self>,
18478    ) {
18479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18480        let selections = self.selections.all::<Point>(cx);
18481        let ranges = selections
18482            .iter()
18483            .map(|s| {
18484                let mut range = s.display_range(&display_map).sorted();
18485                *range.start.column_mut() = 0;
18486                *range.end.column_mut() = display_map.line_len(range.end.row());
18487                let start = range.start.to_point(&display_map);
18488                let end = range.end.to_point(&display_map);
18489                start..end
18490            })
18491            .collect::<Vec<_>>();
18492
18493        self.unfold_ranges(&ranges, true, true, cx);
18494    }
18495
18496    pub fn unfold_at(
18497        &mut self,
18498        buffer_row: MultiBufferRow,
18499        _window: &mut Window,
18500        cx: &mut Context<Self>,
18501    ) {
18502        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18503
18504        let intersection_range = Point::new(buffer_row.0, 0)
18505            ..Point::new(
18506                buffer_row.0,
18507                display_map.buffer_snapshot().line_len(buffer_row),
18508            );
18509
18510        let autoscroll = self
18511            .selections
18512            .all::<Point>(cx)
18513            .iter()
18514            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18515
18516        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18517    }
18518
18519    pub fn unfold_all(
18520        &mut self,
18521        _: &actions::UnfoldAll,
18522        _window: &mut Window,
18523        cx: &mut Context<Self>,
18524    ) {
18525        if self.buffer.read(cx).is_singleton() {
18526            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18527            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18528        } else {
18529            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18530                editor
18531                    .update(cx, |editor, cx| {
18532                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18533                            editor.unfold_buffer(buffer_id, cx);
18534                        }
18535                    })
18536                    .ok();
18537            });
18538        }
18539    }
18540
18541    pub fn fold_selected_ranges(
18542        &mut self,
18543        _: &FoldSelectedRanges,
18544        window: &mut Window,
18545        cx: &mut Context<Self>,
18546    ) {
18547        let selections = self.selections.all_adjusted(cx);
18548        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18549        let ranges = selections
18550            .into_iter()
18551            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18552            .collect::<Vec<_>>();
18553        self.fold_creases(ranges, true, window, cx);
18554    }
18555
18556    pub fn fold_ranges<T: ToOffset + Clone>(
18557        &mut self,
18558        ranges: Vec<Range<T>>,
18559        auto_scroll: bool,
18560        window: &mut Window,
18561        cx: &mut Context<Self>,
18562    ) {
18563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18564        let ranges = ranges
18565            .into_iter()
18566            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18567            .collect::<Vec<_>>();
18568        self.fold_creases(ranges, auto_scroll, window, cx);
18569    }
18570
18571    pub fn fold_creases<T: ToOffset + Clone>(
18572        &mut self,
18573        creases: Vec<Crease<T>>,
18574        auto_scroll: bool,
18575        _window: &mut Window,
18576        cx: &mut Context<Self>,
18577    ) {
18578        if creases.is_empty() {
18579            return;
18580        }
18581
18582        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18583
18584        if auto_scroll {
18585            self.request_autoscroll(Autoscroll::fit(), cx);
18586        }
18587
18588        cx.notify();
18589
18590        self.scrollbar_marker_state.dirty = true;
18591        self.folds_did_change(cx);
18592    }
18593
18594    /// Removes any folds whose ranges intersect any of the given ranges.
18595    pub fn unfold_ranges<T: ToOffset + Clone>(
18596        &mut self,
18597        ranges: &[Range<T>],
18598        inclusive: bool,
18599        auto_scroll: bool,
18600        cx: &mut Context<Self>,
18601    ) {
18602        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18603            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18604        });
18605        self.folds_did_change(cx);
18606    }
18607
18608    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18609        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18610            return;
18611        }
18612        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18613        self.display_map.update(cx, |display_map, cx| {
18614            display_map.fold_buffers([buffer_id], cx)
18615        });
18616        cx.emit(EditorEvent::BufferFoldToggled {
18617            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18618            folded: true,
18619        });
18620        cx.notify();
18621    }
18622
18623    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18624        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18625            return;
18626        }
18627        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18628        self.display_map.update(cx, |display_map, cx| {
18629            display_map.unfold_buffers([buffer_id], cx);
18630        });
18631        cx.emit(EditorEvent::BufferFoldToggled {
18632            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18633            folded: false,
18634        });
18635        cx.notify();
18636    }
18637
18638    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18639        self.display_map.read(cx).is_buffer_folded(buffer)
18640    }
18641
18642    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18643        self.display_map.read(cx).folded_buffers()
18644    }
18645
18646    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18647        self.display_map.update(cx, |display_map, cx| {
18648            display_map.disable_header_for_buffer(buffer_id, cx);
18649        });
18650        cx.notify();
18651    }
18652
18653    /// Removes any folds with the given ranges.
18654    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18655        &mut self,
18656        ranges: &[Range<T>],
18657        type_id: TypeId,
18658        auto_scroll: bool,
18659        cx: &mut Context<Self>,
18660    ) {
18661        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18662            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18663        });
18664        self.folds_did_change(cx);
18665    }
18666
18667    fn remove_folds_with<T: ToOffset + Clone>(
18668        &mut self,
18669        ranges: &[Range<T>],
18670        auto_scroll: bool,
18671        cx: &mut Context<Self>,
18672        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18673    ) {
18674        if ranges.is_empty() {
18675            return;
18676        }
18677
18678        let mut buffers_affected = HashSet::default();
18679        let multi_buffer = self.buffer().read(cx);
18680        for range in ranges {
18681            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18682                buffers_affected.insert(buffer.read(cx).remote_id());
18683            };
18684        }
18685
18686        self.display_map.update(cx, update);
18687
18688        if auto_scroll {
18689            self.request_autoscroll(Autoscroll::fit(), cx);
18690        }
18691
18692        cx.notify();
18693        self.scrollbar_marker_state.dirty = true;
18694        self.active_indent_guides_state.dirty = true;
18695    }
18696
18697    pub fn update_renderer_widths(
18698        &mut self,
18699        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18700        cx: &mut Context<Self>,
18701    ) -> bool {
18702        self.display_map
18703            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18704    }
18705
18706    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18707        self.display_map.read(cx).fold_placeholder.clone()
18708    }
18709
18710    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18711        self.buffer.update(cx, |buffer, cx| {
18712            buffer.set_all_diff_hunks_expanded(cx);
18713        });
18714    }
18715
18716    pub fn expand_all_diff_hunks(
18717        &mut self,
18718        _: &ExpandAllDiffHunks,
18719        _window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        self.buffer.update(cx, |buffer, cx| {
18723            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18724        });
18725    }
18726
18727    pub fn toggle_selected_diff_hunks(
18728        &mut self,
18729        _: &ToggleSelectedDiffHunks,
18730        _window: &mut Window,
18731        cx: &mut Context<Self>,
18732    ) {
18733        let ranges: Vec<_> = self
18734            .selections
18735            .disjoint_anchors()
18736            .iter()
18737            .map(|s| s.range())
18738            .collect();
18739        self.toggle_diff_hunks_in_ranges(ranges, cx);
18740    }
18741
18742    pub fn diff_hunks_in_ranges<'a>(
18743        &'a self,
18744        ranges: &'a [Range<Anchor>],
18745        buffer: &'a MultiBufferSnapshot,
18746    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18747        ranges.iter().flat_map(move |range| {
18748            let end_excerpt_id = range.end.excerpt_id;
18749            let range = range.to_point(buffer);
18750            let mut peek_end = range.end;
18751            if range.end.row < buffer.max_row().0 {
18752                peek_end = Point::new(range.end.row + 1, 0);
18753            }
18754            buffer
18755                .diff_hunks_in_range(range.start..peek_end)
18756                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18757        })
18758    }
18759
18760    pub fn has_stageable_diff_hunks_in_ranges(
18761        &self,
18762        ranges: &[Range<Anchor>],
18763        snapshot: &MultiBufferSnapshot,
18764    ) -> bool {
18765        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18766        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18767    }
18768
18769    pub fn toggle_staged_selected_diff_hunks(
18770        &mut self,
18771        _: &::git::ToggleStaged,
18772        _: &mut Window,
18773        cx: &mut Context<Self>,
18774    ) {
18775        let snapshot = self.buffer.read(cx).snapshot(cx);
18776        let ranges: Vec<_> = self
18777            .selections
18778            .disjoint_anchors()
18779            .iter()
18780            .map(|s| s.range())
18781            .collect();
18782        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18783        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18784    }
18785
18786    pub fn set_render_diff_hunk_controls(
18787        &mut self,
18788        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18789        cx: &mut Context<Self>,
18790    ) {
18791        self.render_diff_hunk_controls = render_diff_hunk_controls;
18792        cx.notify();
18793    }
18794
18795    pub fn stage_and_next(
18796        &mut self,
18797        _: &::git::StageAndNext,
18798        window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        self.do_stage_or_unstage_and_next(true, window, cx);
18802    }
18803
18804    pub fn unstage_and_next(
18805        &mut self,
18806        _: &::git::UnstageAndNext,
18807        window: &mut Window,
18808        cx: &mut Context<Self>,
18809    ) {
18810        self.do_stage_or_unstage_and_next(false, window, cx);
18811    }
18812
18813    pub fn stage_or_unstage_diff_hunks(
18814        &mut self,
18815        stage: bool,
18816        ranges: Vec<Range<Anchor>>,
18817        cx: &mut Context<Self>,
18818    ) {
18819        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18820        cx.spawn(async move |this, cx| {
18821            task.await?;
18822            this.update(cx, |this, cx| {
18823                let snapshot = this.buffer.read(cx).snapshot(cx);
18824                let chunk_by = this
18825                    .diff_hunks_in_ranges(&ranges, &snapshot)
18826                    .chunk_by(|hunk| hunk.buffer_id);
18827                for (buffer_id, hunks) in &chunk_by {
18828                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18829                }
18830            })
18831        })
18832        .detach_and_log_err(cx);
18833    }
18834
18835    fn save_buffers_for_ranges_if_needed(
18836        &mut self,
18837        ranges: &[Range<Anchor>],
18838        cx: &mut Context<Editor>,
18839    ) -> Task<Result<()>> {
18840        let multibuffer = self.buffer.read(cx);
18841        let snapshot = multibuffer.read(cx);
18842        let buffer_ids: HashSet<_> = ranges
18843            .iter()
18844            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18845            .collect();
18846        drop(snapshot);
18847
18848        let mut buffers = HashSet::default();
18849        for buffer_id in buffer_ids {
18850            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18851                let buffer = buffer_entity.read(cx);
18852                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18853                {
18854                    buffers.insert(buffer_entity);
18855                }
18856            }
18857        }
18858
18859        if let Some(project) = &self.project {
18860            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18861        } else {
18862            Task::ready(Ok(()))
18863        }
18864    }
18865
18866    fn do_stage_or_unstage_and_next(
18867        &mut self,
18868        stage: bool,
18869        window: &mut Window,
18870        cx: &mut Context<Self>,
18871    ) {
18872        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18873
18874        if ranges.iter().any(|range| range.start != range.end) {
18875            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18876            return;
18877        }
18878
18879        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18880        let snapshot = self.snapshot(window, cx);
18881        let position = self.selections.newest::<Point>(cx).head();
18882        let mut row = snapshot
18883            .buffer_snapshot()
18884            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18885            .find(|hunk| hunk.row_range.start.0 > position.row)
18886            .map(|hunk| hunk.row_range.start);
18887
18888        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18889        // Outside of the project diff editor, wrap around to the beginning.
18890        if !all_diff_hunks_expanded {
18891            row = row.or_else(|| {
18892                snapshot
18893                    .buffer_snapshot()
18894                    .diff_hunks_in_range(Point::zero()..position)
18895                    .find(|hunk| hunk.row_range.end.0 < position.row)
18896                    .map(|hunk| hunk.row_range.start)
18897            });
18898        }
18899
18900        if let Some(row) = row {
18901            let destination = Point::new(row.0, 0);
18902            let autoscroll = Autoscroll::center();
18903
18904            self.unfold_ranges(&[destination..destination], false, false, cx);
18905            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18906                s.select_ranges([destination..destination]);
18907            });
18908        }
18909    }
18910
18911    fn do_stage_or_unstage(
18912        &self,
18913        stage: bool,
18914        buffer_id: BufferId,
18915        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18916        cx: &mut App,
18917    ) -> Option<()> {
18918        let project = self.project()?;
18919        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18920        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18921        let buffer_snapshot = buffer.read(cx).snapshot();
18922        let file_exists = buffer_snapshot
18923            .file()
18924            .is_some_and(|file| file.disk_state().exists());
18925        diff.update(cx, |diff, cx| {
18926            diff.stage_or_unstage_hunks(
18927                stage,
18928                &hunks
18929                    .map(|hunk| buffer_diff::DiffHunk {
18930                        buffer_range: hunk.buffer_range,
18931                        diff_base_byte_range: hunk.diff_base_byte_range,
18932                        secondary_status: hunk.secondary_status,
18933                        range: Point::zero()..Point::zero(), // unused
18934                    })
18935                    .collect::<Vec<_>>(),
18936                &buffer_snapshot,
18937                file_exists,
18938                cx,
18939            )
18940        });
18941        None
18942    }
18943
18944    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18945        let ranges: Vec<_> = self
18946            .selections
18947            .disjoint_anchors()
18948            .iter()
18949            .map(|s| s.range())
18950            .collect();
18951        self.buffer
18952            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18953    }
18954
18955    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18956        self.buffer.update(cx, |buffer, cx| {
18957            let ranges = vec![Anchor::min()..Anchor::max()];
18958            if !buffer.all_diff_hunks_expanded()
18959                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18960            {
18961                buffer.collapse_diff_hunks(ranges, cx);
18962                true
18963            } else {
18964                false
18965            }
18966        })
18967    }
18968
18969    fn toggle_diff_hunks_in_ranges(
18970        &mut self,
18971        ranges: Vec<Range<Anchor>>,
18972        cx: &mut Context<Editor>,
18973    ) {
18974        self.buffer.update(cx, |buffer, cx| {
18975            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18976            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18977        })
18978    }
18979
18980    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18981        self.buffer.update(cx, |buffer, cx| {
18982            let snapshot = buffer.snapshot(cx);
18983            let excerpt_id = range.end.excerpt_id;
18984            let point_range = range.to_point(&snapshot);
18985            let expand = !buffer.single_hunk_is_expanded(range, cx);
18986            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18987        })
18988    }
18989
18990    pub(crate) fn apply_all_diff_hunks(
18991        &mut self,
18992        _: &ApplyAllDiffHunks,
18993        window: &mut Window,
18994        cx: &mut Context<Self>,
18995    ) {
18996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18997
18998        let buffers = self.buffer.read(cx).all_buffers();
18999        for branch_buffer in buffers {
19000            branch_buffer.update(cx, |branch_buffer, cx| {
19001                branch_buffer.merge_into_base(Vec::new(), cx);
19002            });
19003        }
19004
19005        if let Some(project) = self.project.clone() {
19006            self.save(
19007                SaveOptions {
19008                    format: true,
19009                    autosave: false,
19010                },
19011                project,
19012                window,
19013                cx,
19014            )
19015            .detach_and_log_err(cx);
19016        }
19017    }
19018
19019    pub(crate) fn apply_selected_diff_hunks(
19020        &mut self,
19021        _: &ApplyDiffHunk,
19022        window: &mut Window,
19023        cx: &mut Context<Self>,
19024    ) {
19025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19026        let snapshot = self.snapshot(window, cx);
19027        let hunks = snapshot.hunks_for_ranges(
19028            self.selections
19029                .all(cx)
19030                .into_iter()
19031                .map(|selection| selection.range()),
19032        );
19033        let mut ranges_by_buffer = HashMap::default();
19034        self.transact(window, cx, |editor, _window, cx| {
19035            for hunk in hunks {
19036                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19037                    ranges_by_buffer
19038                        .entry(buffer.clone())
19039                        .or_insert_with(Vec::new)
19040                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19041                }
19042            }
19043
19044            for (buffer, ranges) in ranges_by_buffer {
19045                buffer.update(cx, |buffer, cx| {
19046                    buffer.merge_into_base(ranges, cx);
19047                });
19048            }
19049        });
19050
19051        if let Some(project) = self.project.clone() {
19052            self.save(
19053                SaveOptions {
19054                    format: true,
19055                    autosave: false,
19056                },
19057                project,
19058                window,
19059                cx,
19060            )
19061            .detach_and_log_err(cx);
19062        }
19063    }
19064
19065    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19066        if hovered != self.gutter_hovered {
19067            self.gutter_hovered = hovered;
19068            cx.notify();
19069        }
19070    }
19071
19072    pub fn insert_blocks(
19073        &mut self,
19074        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19075        autoscroll: Option<Autoscroll>,
19076        cx: &mut Context<Self>,
19077    ) -> Vec<CustomBlockId> {
19078        let blocks = self
19079            .display_map
19080            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19081        if let Some(autoscroll) = autoscroll {
19082            self.request_autoscroll(autoscroll, cx);
19083        }
19084        cx.notify();
19085        blocks
19086    }
19087
19088    pub fn resize_blocks(
19089        &mut self,
19090        heights: HashMap<CustomBlockId, u32>,
19091        autoscroll: Option<Autoscroll>,
19092        cx: &mut Context<Self>,
19093    ) {
19094        self.display_map
19095            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19096        if let Some(autoscroll) = autoscroll {
19097            self.request_autoscroll(autoscroll, cx);
19098        }
19099        cx.notify();
19100    }
19101
19102    pub fn replace_blocks(
19103        &mut self,
19104        renderers: HashMap<CustomBlockId, RenderBlock>,
19105        autoscroll: Option<Autoscroll>,
19106        cx: &mut Context<Self>,
19107    ) {
19108        self.display_map
19109            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19110        if let Some(autoscroll) = autoscroll {
19111            self.request_autoscroll(autoscroll, cx);
19112        }
19113        cx.notify();
19114    }
19115
19116    pub fn remove_blocks(
19117        &mut self,
19118        block_ids: HashSet<CustomBlockId>,
19119        autoscroll: Option<Autoscroll>,
19120        cx: &mut Context<Self>,
19121    ) {
19122        self.display_map.update(cx, |display_map, cx| {
19123            display_map.remove_blocks(block_ids, cx)
19124        });
19125        if let Some(autoscroll) = autoscroll {
19126            self.request_autoscroll(autoscroll, cx);
19127        }
19128        cx.notify();
19129    }
19130
19131    pub fn row_for_block(
19132        &self,
19133        block_id: CustomBlockId,
19134        cx: &mut Context<Self>,
19135    ) -> Option<DisplayRow> {
19136        self.display_map
19137            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19138    }
19139
19140    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19141        self.focused_block = Some(focused_block);
19142    }
19143
19144    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19145        self.focused_block.take()
19146    }
19147
19148    pub fn insert_creases(
19149        &mut self,
19150        creases: impl IntoIterator<Item = Crease<Anchor>>,
19151        cx: &mut Context<Self>,
19152    ) -> Vec<CreaseId> {
19153        self.display_map
19154            .update(cx, |map, cx| map.insert_creases(creases, cx))
19155    }
19156
19157    pub fn remove_creases(
19158        &mut self,
19159        ids: impl IntoIterator<Item = CreaseId>,
19160        cx: &mut Context<Self>,
19161    ) -> Vec<(CreaseId, Range<Anchor>)> {
19162        self.display_map
19163            .update(cx, |map, cx| map.remove_creases(ids, cx))
19164    }
19165
19166    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19167        self.display_map
19168            .update(cx, |map, cx| map.snapshot(cx))
19169            .longest_row()
19170    }
19171
19172    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19173        self.display_map
19174            .update(cx, |map, cx| map.snapshot(cx))
19175            .max_point()
19176    }
19177
19178    pub fn text(&self, cx: &App) -> String {
19179        self.buffer.read(cx).read(cx).text()
19180    }
19181
19182    pub fn is_empty(&self, cx: &App) -> bool {
19183        self.buffer.read(cx).read(cx).is_empty()
19184    }
19185
19186    pub fn text_option(&self, cx: &App) -> Option<String> {
19187        let text = self.text(cx);
19188        let text = text.trim();
19189
19190        if text.is_empty() {
19191            return None;
19192        }
19193
19194        Some(text.to_string())
19195    }
19196
19197    pub fn set_text(
19198        &mut self,
19199        text: impl Into<Arc<str>>,
19200        window: &mut Window,
19201        cx: &mut Context<Self>,
19202    ) {
19203        self.transact(window, cx, |this, _, cx| {
19204            this.buffer
19205                .read(cx)
19206                .as_singleton()
19207                .expect("you can only call set_text on editors for singleton buffers")
19208                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19209        });
19210    }
19211
19212    pub fn display_text(&self, cx: &mut App) -> String {
19213        self.display_map
19214            .update(cx, |map, cx| map.snapshot(cx))
19215            .text()
19216    }
19217
19218    fn create_minimap(
19219        &self,
19220        minimap_settings: MinimapSettings,
19221        window: &mut Window,
19222        cx: &mut Context<Self>,
19223    ) -> Option<Entity<Self>> {
19224        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19225            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19226    }
19227
19228    fn initialize_new_minimap(
19229        &self,
19230        minimap_settings: MinimapSettings,
19231        window: &mut Window,
19232        cx: &mut Context<Self>,
19233    ) -> Entity<Self> {
19234        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19235
19236        let mut minimap = Editor::new_internal(
19237            EditorMode::Minimap {
19238                parent: cx.weak_entity(),
19239            },
19240            self.buffer.clone(),
19241            None,
19242            Some(self.display_map.clone()),
19243            window,
19244            cx,
19245        );
19246        minimap.scroll_manager.clone_state(&self.scroll_manager);
19247        minimap.set_text_style_refinement(TextStyleRefinement {
19248            font_size: Some(MINIMAP_FONT_SIZE),
19249            font_weight: Some(MINIMAP_FONT_WEIGHT),
19250            ..Default::default()
19251        });
19252        minimap.update_minimap_configuration(minimap_settings, cx);
19253        cx.new(|_| minimap)
19254    }
19255
19256    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19257        let current_line_highlight = minimap_settings
19258            .current_line_highlight
19259            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19260        self.set_current_line_highlight(Some(current_line_highlight));
19261    }
19262
19263    pub fn minimap(&self) -> Option<&Entity<Self>> {
19264        self.minimap
19265            .as_ref()
19266            .filter(|_| self.minimap_visibility.visible())
19267    }
19268
19269    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19270        let mut wrap_guides = smallvec![];
19271
19272        if self.show_wrap_guides == Some(false) {
19273            return wrap_guides;
19274        }
19275
19276        let settings = self.buffer.read(cx).language_settings(cx);
19277        if settings.show_wrap_guides {
19278            match self.soft_wrap_mode(cx) {
19279                SoftWrap::Column(soft_wrap) => {
19280                    wrap_guides.push((soft_wrap as usize, true));
19281                }
19282                SoftWrap::Bounded(soft_wrap) => {
19283                    wrap_guides.push((soft_wrap as usize, true));
19284                }
19285                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19286            }
19287            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19288        }
19289
19290        wrap_guides
19291    }
19292
19293    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19294        let settings = self.buffer.read(cx).language_settings(cx);
19295        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19296        match mode {
19297            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19298                SoftWrap::None
19299            }
19300            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19301            language_settings::SoftWrap::PreferredLineLength => {
19302                SoftWrap::Column(settings.preferred_line_length)
19303            }
19304            language_settings::SoftWrap::Bounded => {
19305                SoftWrap::Bounded(settings.preferred_line_length)
19306            }
19307        }
19308    }
19309
19310    pub fn set_soft_wrap_mode(
19311        &mut self,
19312        mode: language_settings::SoftWrap,
19313
19314        cx: &mut Context<Self>,
19315    ) {
19316        self.soft_wrap_mode_override = Some(mode);
19317        cx.notify();
19318    }
19319
19320    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19321        self.hard_wrap = hard_wrap;
19322        cx.notify();
19323    }
19324
19325    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19326        self.text_style_refinement = Some(style);
19327    }
19328
19329    /// called by the Element so we know what style we were most recently rendered with.
19330    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19331        // We intentionally do not inform the display map about the minimap style
19332        // so that wrapping is not recalculated and stays consistent for the editor
19333        // and its linked minimap.
19334        if !self.mode.is_minimap() {
19335            let font = style.text.font();
19336            let font_size = style.text.font_size.to_pixels(window.rem_size());
19337            let display_map = self
19338                .placeholder_display_map
19339                .as_ref()
19340                .filter(|_| self.is_empty(cx))
19341                .unwrap_or(&self.display_map);
19342
19343            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19344        }
19345        self.style = Some(style);
19346    }
19347
19348    pub fn style(&self) -> Option<&EditorStyle> {
19349        self.style.as_ref()
19350    }
19351
19352    // Called by the element. This method is not designed to be called outside of the editor
19353    // element's layout code because it does not notify when rewrapping is computed synchronously.
19354    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19355        if self.is_empty(cx) {
19356            self.placeholder_display_map
19357                .as_ref()
19358                .map_or(false, |display_map| {
19359                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19360                })
19361        } else {
19362            self.display_map
19363                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19364        }
19365    }
19366
19367    pub fn set_soft_wrap(&mut self) {
19368        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19369    }
19370
19371    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19372        if self.soft_wrap_mode_override.is_some() {
19373            self.soft_wrap_mode_override.take();
19374        } else {
19375            let soft_wrap = match self.soft_wrap_mode(cx) {
19376                SoftWrap::GitDiff => return,
19377                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19378                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19379                    language_settings::SoftWrap::None
19380                }
19381            };
19382            self.soft_wrap_mode_override = Some(soft_wrap);
19383        }
19384        cx.notify();
19385    }
19386
19387    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19388        let Some(workspace) = self.workspace() else {
19389            return;
19390        };
19391        let fs = workspace.read(cx).app_state().fs.clone();
19392        let current_show = TabBarSettings::get_global(cx).show;
19393        update_settings_file(fs, cx, move |setting, _| {
19394            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19395        });
19396    }
19397
19398    pub fn toggle_indent_guides(
19399        &mut self,
19400        _: &ToggleIndentGuides,
19401        _: &mut Window,
19402        cx: &mut Context<Self>,
19403    ) {
19404        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19405            self.buffer
19406                .read(cx)
19407                .language_settings(cx)
19408                .indent_guides
19409                .enabled
19410        });
19411        self.show_indent_guides = Some(!currently_enabled);
19412        cx.notify();
19413    }
19414
19415    fn should_show_indent_guides(&self) -> Option<bool> {
19416        self.show_indent_guides
19417    }
19418
19419    pub fn toggle_line_numbers(
19420        &mut self,
19421        _: &ToggleLineNumbers,
19422        _: &mut Window,
19423        cx: &mut Context<Self>,
19424    ) {
19425        let mut editor_settings = EditorSettings::get_global(cx).clone();
19426        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19427        EditorSettings::override_global(editor_settings, cx);
19428    }
19429
19430    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19431        if let Some(show_line_numbers) = self.show_line_numbers {
19432            return show_line_numbers;
19433        }
19434        EditorSettings::get_global(cx).gutter.line_numbers
19435    }
19436
19437    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19438        self.use_relative_line_numbers
19439            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19440    }
19441
19442    pub fn toggle_relative_line_numbers(
19443        &mut self,
19444        _: &ToggleRelativeLineNumbers,
19445        _: &mut Window,
19446        cx: &mut Context<Self>,
19447    ) {
19448        let is_relative = self.should_use_relative_line_numbers(cx);
19449        self.set_relative_line_number(Some(!is_relative), cx)
19450    }
19451
19452    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19453        self.use_relative_line_numbers = is_relative;
19454        cx.notify();
19455    }
19456
19457    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19458        self.show_gutter = show_gutter;
19459        cx.notify();
19460    }
19461
19462    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19463        self.show_scrollbars = ScrollbarAxes {
19464            horizontal: show,
19465            vertical: show,
19466        };
19467        cx.notify();
19468    }
19469
19470    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19471        self.show_scrollbars.vertical = show;
19472        cx.notify();
19473    }
19474
19475    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19476        self.show_scrollbars.horizontal = show;
19477        cx.notify();
19478    }
19479
19480    pub fn set_minimap_visibility(
19481        &mut self,
19482        minimap_visibility: MinimapVisibility,
19483        window: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) {
19486        if self.minimap_visibility != minimap_visibility {
19487            if minimap_visibility.visible() && self.minimap.is_none() {
19488                let minimap_settings = EditorSettings::get_global(cx).minimap;
19489                self.minimap =
19490                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19491            }
19492            self.minimap_visibility = minimap_visibility;
19493            cx.notify();
19494        }
19495    }
19496
19497    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19498        self.set_show_scrollbars(false, cx);
19499        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19500    }
19501
19502    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19503        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19504    }
19505
19506    /// Normally the text in full mode and auto height editors is padded on the
19507    /// left side by roughly half a character width for improved hit testing.
19508    ///
19509    /// Use this method to disable this for cases where this is not wanted (e.g.
19510    /// if you want to align the editor text with some other text above or below)
19511    /// or if you want to add this padding to single-line editors.
19512    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19513        self.offset_content = offset_content;
19514        cx.notify();
19515    }
19516
19517    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19518        self.show_line_numbers = Some(show_line_numbers);
19519        cx.notify();
19520    }
19521
19522    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19523        self.disable_expand_excerpt_buttons = true;
19524        cx.notify();
19525    }
19526
19527    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19528        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19529        cx.notify();
19530    }
19531
19532    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19533        self.show_code_actions = Some(show_code_actions);
19534        cx.notify();
19535    }
19536
19537    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19538        self.show_runnables = Some(show_runnables);
19539        cx.notify();
19540    }
19541
19542    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19543        self.show_breakpoints = Some(show_breakpoints);
19544        cx.notify();
19545    }
19546
19547    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19548        if self.display_map.read(cx).masked != masked {
19549            self.display_map.update(cx, |map, _| map.masked = masked);
19550        }
19551        cx.notify()
19552    }
19553
19554    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19555        self.show_wrap_guides = Some(show_wrap_guides);
19556        cx.notify();
19557    }
19558
19559    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19560        self.show_indent_guides = Some(show_indent_guides);
19561        cx.notify();
19562    }
19563
19564    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19565        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19566            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19567                && let Some(dir) = file.abs_path(cx).parent()
19568            {
19569                return Some(dir.to_owned());
19570            }
19571        }
19572
19573        None
19574    }
19575
19576    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19577        self.active_excerpt(cx)?
19578            .1
19579            .read(cx)
19580            .file()
19581            .and_then(|f| f.as_local())
19582    }
19583
19584    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19585        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19586            let buffer = buffer.read(cx);
19587            if let Some(project_path) = buffer.project_path(cx) {
19588                let project = self.project()?.read(cx);
19589                project.absolute_path(&project_path, cx)
19590            } else {
19591                buffer
19592                    .file()
19593                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19594            }
19595        })
19596    }
19597
19598    pub fn reveal_in_finder(
19599        &mut self,
19600        _: &RevealInFileManager,
19601        _window: &mut Window,
19602        cx: &mut Context<Self>,
19603    ) {
19604        if let Some(target) = self.target_file(cx) {
19605            cx.reveal_path(&target.abs_path(cx));
19606        }
19607    }
19608
19609    pub fn copy_path(
19610        &mut self,
19611        _: &zed_actions::workspace::CopyPath,
19612        _window: &mut Window,
19613        cx: &mut Context<Self>,
19614    ) {
19615        if let Some(path) = self.target_file_abs_path(cx)
19616            && let Some(path) = path.to_str()
19617        {
19618            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19619        } else {
19620            cx.propagate();
19621        }
19622    }
19623
19624    pub fn copy_relative_path(
19625        &mut self,
19626        _: &zed_actions::workspace::CopyRelativePath,
19627        _window: &mut Window,
19628        cx: &mut Context<Self>,
19629    ) {
19630        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19631            let project = self.project()?.read(cx);
19632            let path = buffer.read(cx).file()?.path();
19633            let path = path.display(project.path_style(cx));
19634            Some(path)
19635        }) {
19636            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19637        } else {
19638            cx.propagate();
19639        }
19640    }
19641
19642    /// Returns the project path for the editor's buffer, if any buffer is
19643    /// opened in the editor.
19644    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19645        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19646            buffer.read(cx).project_path(cx)
19647        } else {
19648            None
19649        }
19650    }
19651
19652    // Returns true if the editor handled a go-to-line request
19653    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19654        maybe!({
19655            let breakpoint_store = self.breakpoint_store.as_ref()?;
19656
19657            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19658            else {
19659                self.clear_row_highlights::<ActiveDebugLine>();
19660                return None;
19661            };
19662
19663            let position = active_stack_frame.position;
19664            let buffer_id = position.buffer_id?;
19665            let snapshot = self
19666                .project
19667                .as_ref()?
19668                .read(cx)
19669                .buffer_for_id(buffer_id, cx)?
19670                .read(cx)
19671                .snapshot();
19672
19673            let mut handled = false;
19674            for (id, ExcerptRange { context, .. }) in
19675                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19676            {
19677                if context.start.cmp(&position, &snapshot).is_ge()
19678                    || context.end.cmp(&position, &snapshot).is_lt()
19679                {
19680                    continue;
19681                }
19682                let snapshot = self.buffer.read(cx).snapshot(cx);
19683                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19684
19685                handled = true;
19686                self.clear_row_highlights::<ActiveDebugLine>();
19687
19688                self.go_to_line::<ActiveDebugLine>(
19689                    multibuffer_anchor,
19690                    Some(cx.theme().colors().editor_debugger_active_line_background),
19691                    window,
19692                    cx,
19693                );
19694
19695                cx.notify();
19696            }
19697
19698            handled.then_some(())
19699        })
19700        .is_some()
19701    }
19702
19703    pub fn copy_file_name_without_extension(
19704        &mut self,
19705        _: &CopyFileNameWithoutExtension,
19706        _: &mut Window,
19707        cx: &mut Context<Self>,
19708    ) {
19709        if let Some(file) = self.target_file(cx)
19710            && let Some(file_stem) = file.path().file_stem()
19711        {
19712            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19713        }
19714    }
19715
19716    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19717        if let Some(file) = self.target_file(cx)
19718            && let Some(name) = file.path().file_name()
19719        {
19720            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19721        }
19722    }
19723
19724    pub fn toggle_git_blame(
19725        &mut self,
19726        _: &::git::Blame,
19727        window: &mut Window,
19728        cx: &mut Context<Self>,
19729    ) {
19730        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19731
19732        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19733            self.start_git_blame(true, window, cx);
19734        }
19735
19736        cx.notify();
19737    }
19738
19739    pub fn toggle_git_blame_inline(
19740        &mut self,
19741        _: &ToggleGitBlameInline,
19742        window: &mut Window,
19743        cx: &mut Context<Self>,
19744    ) {
19745        self.toggle_git_blame_inline_internal(true, window, cx);
19746        cx.notify();
19747    }
19748
19749    pub fn open_git_blame_commit(
19750        &mut self,
19751        _: &OpenGitBlameCommit,
19752        window: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        self.open_git_blame_commit_internal(window, cx);
19756    }
19757
19758    fn open_git_blame_commit_internal(
19759        &mut self,
19760        window: &mut Window,
19761        cx: &mut Context<Self>,
19762    ) -> Option<()> {
19763        let blame = self.blame.as_ref()?;
19764        let snapshot = self.snapshot(window, cx);
19765        let cursor = self.selections.newest::<Point>(cx).head();
19766        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19767        let (_, blame_entry) = blame
19768            .update(cx, |blame, cx| {
19769                blame
19770                    .blame_for_rows(
19771                        &[RowInfo {
19772                            buffer_id: Some(buffer.remote_id()),
19773                            buffer_row: Some(point.row),
19774                            ..Default::default()
19775                        }],
19776                        cx,
19777                    )
19778                    .next()
19779            })
19780            .flatten()?;
19781        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19782        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19783        let workspace = self.workspace()?.downgrade();
19784        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19785        None
19786    }
19787
19788    pub fn git_blame_inline_enabled(&self) -> bool {
19789        self.git_blame_inline_enabled
19790    }
19791
19792    pub fn toggle_selection_menu(
19793        &mut self,
19794        _: &ToggleSelectionMenu,
19795        _: &mut Window,
19796        cx: &mut Context<Self>,
19797    ) {
19798        self.show_selection_menu = self
19799            .show_selection_menu
19800            .map(|show_selections_menu| !show_selections_menu)
19801            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19802
19803        cx.notify();
19804    }
19805
19806    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19807        self.show_selection_menu
19808            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19809    }
19810
19811    fn start_git_blame(
19812        &mut self,
19813        user_triggered: bool,
19814        window: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        if let Some(project) = self.project() {
19818            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19819                && buffer.read(cx).file().is_none()
19820            {
19821                return;
19822            }
19823
19824            let focused = self.focus_handle(cx).contains_focused(window, cx);
19825
19826            let project = project.clone();
19827            let blame = cx
19828                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19829            self.blame_subscription =
19830                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19831            self.blame = Some(blame);
19832        }
19833    }
19834
19835    fn toggle_git_blame_inline_internal(
19836        &mut self,
19837        user_triggered: bool,
19838        window: &mut Window,
19839        cx: &mut Context<Self>,
19840    ) {
19841        if self.git_blame_inline_enabled {
19842            self.git_blame_inline_enabled = false;
19843            self.show_git_blame_inline = false;
19844            self.show_git_blame_inline_delay_task.take();
19845        } else {
19846            self.git_blame_inline_enabled = true;
19847            self.start_git_blame_inline(user_triggered, window, cx);
19848        }
19849
19850        cx.notify();
19851    }
19852
19853    fn start_git_blame_inline(
19854        &mut self,
19855        user_triggered: bool,
19856        window: &mut Window,
19857        cx: &mut Context<Self>,
19858    ) {
19859        self.start_git_blame(user_triggered, window, cx);
19860
19861        if ProjectSettings::get_global(cx)
19862            .git
19863            .inline_blame_delay()
19864            .is_some()
19865        {
19866            self.start_inline_blame_timer(window, cx);
19867        } else {
19868            self.show_git_blame_inline = true
19869        }
19870    }
19871
19872    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19873        self.blame.as_ref()
19874    }
19875
19876    pub fn show_git_blame_gutter(&self) -> bool {
19877        self.show_git_blame_gutter
19878    }
19879
19880    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19881        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19882    }
19883
19884    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19885        self.show_git_blame_inline
19886            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19887            && !self.newest_selection_head_on_empty_line(cx)
19888            && self.has_blame_entries(cx)
19889    }
19890
19891    fn has_blame_entries(&self, cx: &App) -> bool {
19892        self.blame()
19893            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19894    }
19895
19896    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19897        let cursor_anchor = self.selections.newest_anchor().head();
19898
19899        let snapshot = self.buffer.read(cx).snapshot(cx);
19900        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19901
19902        snapshot.line_len(buffer_row) == 0
19903    }
19904
19905    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19906        let buffer_and_selection = maybe!({
19907            let selection = self.selections.newest::<Point>(cx);
19908            let selection_range = selection.range();
19909
19910            let multi_buffer = self.buffer().read(cx);
19911            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19912            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19913
19914            let (buffer, range, _) = if selection.reversed {
19915                buffer_ranges.first()
19916            } else {
19917                buffer_ranges.last()
19918            }?;
19919
19920            let selection = text::ToPoint::to_point(&range.start, buffer).row
19921                ..text::ToPoint::to_point(&range.end, buffer).row;
19922            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19923        });
19924
19925        let Some((buffer, selection)) = buffer_and_selection else {
19926            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19927        };
19928
19929        let Some(project) = self.project() else {
19930            return Task::ready(Err(anyhow!("editor does not have project")));
19931        };
19932
19933        project.update(cx, |project, cx| {
19934            project.get_permalink_to_line(&buffer, selection, cx)
19935        })
19936    }
19937
19938    pub fn copy_permalink_to_line(
19939        &mut self,
19940        _: &CopyPermalinkToLine,
19941        window: &mut Window,
19942        cx: &mut Context<Self>,
19943    ) {
19944        let permalink_task = self.get_permalink_to_line(cx);
19945        let workspace = self.workspace();
19946
19947        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19948            Ok(permalink) => {
19949                cx.update(|_, cx| {
19950                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19951                })
19952                .ok();
19953            }
19954            Err(err) => {
19955                let message = format!("Failed to copy permalink: {err}");
19956
19957                anyhow::Result::<()>::Err(err).log_err();
19958
19959                if let Some(workspace) = workspace {
19960                    workspace
19961                        .update_in(cx, |workspace, _, cx| {
19962                            struct CopyPermalinkToLine;
19963
19964                            workspace.show_toast(
19965                                Toast::new(
19966                                    NotificationId::unique::<CopyPermalinkToLine>(),
19967                                    message,
19968                                ),
19969                                cx,
19970                            )
19971                        })
19972                        .ok();
19973                }
19974            }
19975        })
19976        .detach();
19977    }
19978
19979    pub fn copy_file_location(
19980        &mut self,
19981        _: &CopyFileLocation,
19982        _: &mut Window,
19983        cx: &mut Context<Self>,
19984    ) {
19985        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19986        if let Some(file) = self.target_file(cx) {
19987            let path = file.path().display(file.path_style(cx));
19988            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19989        }
19990    }
19991
19992    pub fn open_permalink_to_line(
19993        &mut self,
19994        _: &OpenPermalinkToLine,
19995        window: &mut Window,
19996        cx: &mut Context<Self>,
19997    ) {
19998        let permalink_task = self.get_permalink_to_line(cx);
19999        let workspace = self.workspace();
20000
20001        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20002            Ok(permalink) => {
20003                cx.update(|_, cx| {
20004                    cx.open_url(permalink.as_ref());
20005                })
20006                .ok();
20007            }
20008            Err(err) => {
20009                let message = format!("Failed to open permalink: {err}");
20010
20011                anyhow::Result::<()>::Err(err).log_err();
20012
20013                if let Some(workspace) = workspace {
20014                    workspace
20015                        .update(cx, |workspace, cx| {
20016                            struct OpenPermalinkToLine;
20017
20018                            workspace.show_toast(
20019                                Toast::new(
20020                                    NotificationId::unique::<OpenPermalinkToLine>(),
20021                                    message,
20022                                ),
20023                                cx,
20024                            )
20025                        })
20026                        .ok();
20027                }
20028            }
20029        })
20030        .detach();
20031    }
20032
20033    pub fn insert_uuid_v4(
20034        &mut self,
20035        _: &InsertUuidV4,
20036        window: &mut Window,
20037        cx: &mut Context<Self>,
20038    ) {
20039        self.insert_uuid(UuidVersion::V4, window, cx);
20040    }
20041
20042    pub fn insert_uuid_v7(
20043        &mut self,
20044        _: &InsertUuidV7,
20045        window: &mut Window,
20046        cx: &mut Context<Self>,
20047    ) {
20048        self.insert_uuid(UuidVersion::V7, window, cx);
20049    }
20050
20051    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20053        self.transact(window, cx, |this, window, cx| {
20054            let edits = this
20055                .selections
20056                .all::<Point>(cx)
20057                .into_iter()
20058                .map(|selection| {
20059                    let uuid = match version {
20060                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20061                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20062                    };
20063
20064                    (selection.range(), uuid.to_string())
20065                });
20066            this.edit(edits, cx);
20067            this.refresh_edit_prediction(true, false, window, cx);
20068        });
20069    }
20070
20071    pub fn open_selections_in_multibuffer(
20072        &mut self,
20073        _: &OpenSelectionsInMultibuffer,
20074        window: &mut Window,
20075        cx: &mut Context<Self>,
20076    ) {
20077        let multibuffer = self.buffer.read(cx);
20078
20079        let Some(buffer) = multibuffer.as_singleton() else {
20080            return;
20081        };
20082
20083        let Some(workspace) = self.workspace() else {
20084            return;
20085        };
20086
20087        let title = multibuffer.title(cx).to_string();
20088
20089        let locations = self
20090            .selections
20091            .all_anchors(cx)
20092            .iter()
20093            .map(|selection| {
20094                (
20095                    buffer.clone(),
20096                    (selection.start.text_anchor..selection.end.text_anchor)
20097                        .to_point(buffer.read(cx)),
20098                )
20099            })
20100            .into_group_map();
20101
20102        cx.spawn_in(window, async move |_, cx| {
20103            workspace.update_in(cx, |workspace, window, cx| {
20104                Self::open_locations_in_multibuffer(
20105                    workspace,
20106                    locations,
20107                    format!("Selections for '{title}'"),
20108                    false,
20109                    MultibufferSelectionMode::All,
20110                    window,
20111                    cx,
20112                );
20113            })
20114        })
20115        .detach();
20116    }
20117
20118    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20119    /// last highlight added will be used.
20120    ///
20121    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20122    pub fn highlight_rows<T: 'static>(
20123        &mut self,
20124        range: Range<Anchor>,
20125        color: Hsla,
20126        options: RowHighlightOptions,
20127        cx: &mut Context<Self>,
20128    ) {
20129        let snapshot = self.buffer().read(cx).snapshot(cx);
20130        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20131        let ix = row_highlights.binary_search_by(|highlight| {
20132            Ordering::Equal
20133                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20134                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20135        });
20136
20137        if let Err(mut ix) = ix {
20138            let index = post_inc(&mut self.highlight_order);
20139
20140            // If this range intersects with the preceding highlight, then merge it with
20141            // the preceding highlight. Otherwise insert a new highlight.
20142            let mut merged = false;
20143            if ix > 0 {
20144                let prev_highlight = &mut row_highlights[ix - 1];
20145                if prev_highlight
20146                    .range
20147                    .end
20148                    .cmp(&range.start, &snapshot)
20149                    .is_ge()
20150                {
20151                    ix -= 1;
20152                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20153                        prev_highlight.range.end = range.end;
20154                    }
20155                    merged = true;
20156                    prev_highlight.index = index;
20157                    prev_highlight.color = color;
20158                    prev_highlight.options = options;
20159                }
20160            }
20161
20162            if !merged {
20163                row_highlights.insert(
20164                    ix,
20165                    RowHighlight {
20166                        range,
20167                        index,
20168                        color,
20169                        options,
20170                        type_id: TypeId::of::<T>(),
20171                    },
20172                );
20173            }
20174
20175            // If any of the following highlights intersect with this one, merge them.
20176            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20177                let highlight = &row_highlights[ix];
20178                if next_highlight
20179                    .range
20180                    .start
20181                    .cmp(&highlight.range.end, &snapshot)
20182                    .is_le()
20183                {
20184                    if next_highlight
20185                        .range
20186                        .end
20187                        .cmp(&highlight.range.end, &snapshot)
20188                        .is_gt()
20189                    {
20190                        row_highlights[ix].range.end = next_highlight.range.end;
20191                    }
20192                    row_highlights.remove(ix + 1);
20193                } else {
20194                    break;
20195                }
20196            }
20197        }
20198    }
20199
20200    /// Remove any highlighted row ranges of the given type that intersect the
20201    /// given ranges.
20202    pub fn remove_highlighted_rows<T: 'static>(
20203        &mut self,
20204        ranges_to_remove: Vec<Range<Anchor>>,
20205        cx: &mut Context<Self>,
20206    ) {
20207        let snapshot = self.buffer().read(cx).snapshot(cx);
20208        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20209        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20210        row_highlights.retain(|highlight| {
20211            while let Some(range_to_remove) = ranges_to_remove.peek() {
20212                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20213                    Ordering::Less | Ordering::Equal => {
20214                        ranges_to_remove.next();
20215                    }
20216                    Ordering::Greater => {
20217                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20218                            Ordering::Less | Ordering::Equal => {
20219                                return false;
20220                            }
20221                            Ordering::Greater => break,
20222                        }
20223                    }
20224                }
20225            }
20226
20227            true
20228        })
20229    }
20230
20231    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20232    pub fn clear_row_highlights<T: 'static>(&mut self) {
20233        self.highlighted_rows.remove(&TypeId::of::<T>());
20234    }
20235
20236    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20237    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20238        self.highlighted_rows
20239            .get(&TypeId::of::<T>())
20240            .map_or(&[] as &[_], |vec| vec.as_slice())
20241            .iter()
20242            .map(|highlight| (highlight.range.clone(), highlight.color))
20243    }
20244
20245    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20246    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20247    /// Allows to ignore certain kinds of highlights.
20248    pub fn highlighted_display_rows(
20249        &self,
20250        window: &mut Window,
20251        cx: &mut App,
20252    ) -> BTreeMap<DisplayRow, LineHighlight> {
20253        let snapshot = self.snapshot(window, cx);
20254        let mut used_highlight_orders = HashMap::default();
20255        self.highlighted_rows
20256            .iter()
20257            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20258            .fold(
20259                BTreeMap::<DisplayRow, LineHighlight>::new(),
20260                |mut unique_rows, highlight| {
20261                    let start = highlight.range.start.to_display_point(&snapshot);
20262                    let end = highlight.range.end.to_display_point(&snapshot);
20263                    let start_row = start.row().0;
20264                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20265                        && end.column() == 0
20266                    {
20267                        end.row().0.saturating_sub(1)
20268                    } else {
20269                        end.row().0
20270                    };
20271                    for row in start_row..=end_row {
20272                        let used_index =
20273                            used_highlight_orders.entry(row).or_insert(highlight.index);
20274                        if highlight.index >= *used_index {
20275                            *used_index = highlight.index;
20276                            unique_rows.insert(
20277                                DisplayRow(row),
20278                                LineHighlight {
20279                                    include_gutter: highlight.options.include_gutter,
20280                                    border: None,
20281                                    background: highlight.color.into(),
20282                                    type_id: Some(highlight.type_id),
20283                                },
20284                            );
20285                        }
20286                    }
20287                    unique_rows
20288                },
20289            )
20290    }
20291
20292    pub fn highlighted_display_row_for_autoscroll(
20293        &self,
20294        snapshot: &DisplaySnapshot,
20295    ) -> Option<DisplayRow> {
20296        self.highlighted_rows
20297            .values()
20298            .flat_map(|highlighted_rows| highlighted_rows.iter())
20299            .filter_map(|highlight| {
20300                if highlight.options.autoscroll {
20301                    Some(highlight.range.start.to_display_point(snapshot).row())
20302                } else {
20303                    None
20304                }
20305            })
20306            .min()
20307    }
20308
20309    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20310        self.highlight_background::<SearchWithinRange>(
20311            ranges,
20312            |colors| colors.colors().editor_document_highlight_read_background,
20313            cx,
20314        )
20315    }
20316
20317    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20318        self.breadcrumb_header = Some(new_header);
20319    }
20320
20321    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20322        self.clear_background_highlights::<SearchWithinRange>(cx);
20323    }
20324
20325    pub fn highlight_background<T: 'static>(
20326        &mut self,
20327        ranges: &[Range<Anchor>],
20328        color_fetcher: fn(&Theme) -> Hsla,
20329        cx: &mut Context<Self>,
20330    ) {
20331        self.background_highlights.insert(
20332            HighlightKey::Type(TypeId::of::<T>()),
20333            (color_fetcher, Arc::from(ranges)),
20334        );
20335        self.scrollbar_marker_state.dirty = true;
20336        cx.notify();
20337    }
20338
20339    pub fn highlight_background_key<T: 'static>(
20340        &mut self,
20341        key: usize,
20342        ranges: &[Range<Anchor>],
20343        color_fetcher: fn(&Theme) -> Hsla,
20344        cx: &mut Context<Self>,
20345    ) {
20346        self.background_highlights.insert(
20347            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20348            (color_fetcher, Arc::from(ranges)),
20349        );
20350        self.scrollbar_marker_state.dirty = true;
20351        cx.notify();
20352    }
20353
20354    pub fn clear_background_highlights<T: 'static>(
20355        &mut self,
20356        cx: &mut Context<Self>,
20357    ) -> Option<BackgroundHighlight> {
20358        let text_highlights = self
20359            .background_highlights
20360            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20361        if !text_highlights.1.is_empty() {
20362            self.scrollbar_marker_state.dirty = true;
20363            cx.notify();
20364        }
20365        Some(text_highlights)
20366    }
20367
20368    pub fn highlight_gutter<T: 'static>(
20369        &mut self,
20370        ranges: impl Into<Vec<Range<Anchor>>>,
20371        color_fetcher: fn(&App) -> Hsla,
20372        cx: &mut Context<Self>,
20373    ) {
20374        self.gutter_highlights
20375            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20376        cx.notify();
20377    }
20378
20379    pub fn clear_gutter_highlights<T: 'static>(
20380        &mut self,
20381        cx: &mut Context<Self>,
20382    ) -> Option<GutterHighlight> {
20383        cx.notify();
20384        self.gutter_highlights.remove(&TypeId::of::<T>())
20385    }
20386
20387    pub fn insert_gutter_highlight<T: 'static>(
20388        &mut self,
20389        range: Range<Anchor>,
20390        color_fetcher: fn(&App) -> Hsla,
20391        cx: &mut Context<Self>,
20392    ) {
20393        let snapshot = self.buffer().read(cx).snapshot(cx);
20394        let mut highlights = self
20395            .gutter_highlights
20396            .remove(&TypeId::of::<T>())
20397            .map(|(_, highlights)| highlights)
20398            .unwrap_or_default();
20399        let ix = highlights.binary_search_by(|highlight| {
20400            Ordering::Equal
20401                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20402                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20403        });
20404        if let Err(ix) = ix {
20405            highlights.insert(ix, range);
20406        }
20407        self.gutter_highlights
20408            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20409    }
20410
20411    pub fn remove_gutter_highlights<T: 'static>(
20412        &mut self,
20413        ranges_to_remove: Vec<Range<Anchor>>,
20414        cx: &mut Context<Self>,
20415    ) {
20416        let snapshot = self.buffer().read(cx).snapshot(cx);
20417        let Some((color_fetcher, mut gutter_highlights)) =
20418            self.gutter_highlights.remove(&TypeId::of::<T>())
20419        else {
20420            return;
20421        };
20422        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20423        gutter_highlights.retain(|highlight| {
20424            while let Some(range_to_remove) = ranges_to_remove.peek() {
20425                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20426                    Ordering::Less | Ordering::Equal => {
20427                        ranges_to_remove.next();
20428                    }
20429                    Ordering::Greater => {
20430                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20431                            Ordering::Less | Ordering::Equal => {
20432                                return false;
20433                            }
20434                            Ordering::Greater => break,
20435                        }
20436                    }
20437                }
20438            }
20439
20440            true
20441        });
20442        self.gutter_highlights
20443            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20444    }
20445
20446    #[cfg(feature = "test-support")]
20447    pub fn all_text_highlights(
20448        &self,
20449        window: &mut Window,
20450        cx: &mut Context<Self>,
20451    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20452        let snapshot = self.snapshot(window, cx);
20453        self.display_map.update(cx, |display_map, _| {
20454            display_map
20455                .all_text_highlights()
20456                .map(|highlight| {
20457                    let (style, ranges) = highlight.as_ref();
20458                    (
20459                        *style,
20460                        ranges
20461                            .iter()
20462                            .map(|range| range.clone().to_display_points(&snapshot))
20463                            .collect(),
20464                    )
20465                })
20466                .collect()
20467        })
20468    }
20469
20470    #[cfg(feature = "test-support")]
20471    pub fn all_text_background_highlights(
20472        &self,
20473        window: &mut Window,
20474        cx: &mut Context<Self>,
20475    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20476        let snapshot = self.snapshot(window, cx);
20477        let buffer = &snapshot.buffer_snapshot();
20478        let start = buffer.anchor_before(0);
20479        let end = buffer.anchor_after(buffer.len());
20480        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20481    }
20482
20483    #[cfg(any(test, feature = "test-support"))]
20484    pub fn sorted_background_highlights_in_range(
20485        &self,
20486        search_range: Range<Anchor>,
20487        display_snapshot: &DisplaySnapshot,
20488        theme: &Theme,
20489    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20490        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20491        res.sort_by(|a, b| {
20492            a.0.start
20493                .cmp(&b.0.start)
20494                .then_with(|| a.0.end.cmp(&b.0.end))
20495                .then_with(|| a.1.cmp(&b.1))
20496        });
20497        res
20498    }
20499
20500    #[cfg(feature = "test-support")]
20501    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20502        let snapshot = self.buffer().read(cx).snapshot(cx);
20503
20504        let highlights = self
20505            .background_highlights
20506            .get(&HighlightKey::Type(TypeId::of::<
20507                items::BufferSearchHighlights,
20508            >()));
20509
20510        if let Some((_color, ranges)) = highlights {
20511            ranges
20512                .iter()
20513                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20514                .collect_vec()
20515        } else {
20516            vec![]
20517        }
20518    }
20519
20520    fn document_highlights_for_position<'a>(
20521        &'a self,
20522        position: Anchor,
20523        buffer: &'a MultiBufferSnapshot,
20524    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20525        let read_highlights = self
20526            .background_highlights
20527            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20528            .map(|h| &h.1);
20529        let write_highlights = self
20530            .background_highlights
20531            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20532            .map(|h| &h.1);
20533        let left_position = position.bias_left(buffer);
20534        let right_position = position.bias_right(buffer);
20535        read_highlights
20536            .into_iter()
20537            .chain(write_highlights)
20538            .flat_map(move |ranges| {
20539                let start_ix = match ranges.binary_search_by(|probe| {
20540                    let cmp = probe.end.cmp(&left_position, buffer);
20541                    if cmp.is_ge() {
20542                        Ordering::Greater
20543                    } else {
20544                        Ordering::Less
20545                    }
20546                }) {
20547                    Ok(i) | Err(i) => i,
20548                };
20549
20550                ranges[start_ix..]
20551                    .iter()
20552                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20553            })
20554    }
20555
20556    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20557        self.background_highlights
20558            .get(&HighlightKey::Type(TypeId::of::<T>()))
20559            .is_some_and(|(_, highlights)| !highlights.is_empty())
20560    }
20561
20562    /// Returns all background highlights for a given range.
20563    ///
20564    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20565    pub fn background_highlights_in_range(
20566        &self,
20567        search_range: Range<Anchor>,
20568        display_snapshot: &DisplaySnapshot,
20569        theme: &Theme,
20570    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20571        let mut results = Vec::new();
20572        for (color_fetcher, ranges) in self.background_highlights.values() {
20573            let color = color_fetcher(theme);
20574            let start_ix = match ranges.binary_search_by(|probe| {
20575                let cmp = probe
20576                    .end
20577                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20578                if cmp.is_gt() {
20579                    Ordering::Greater
20580                } else {
20581                    Ordering::Less
20582                }
20583            }) {
20584                Ok(i) | Err(i) => i,
20585            };
20586            for range in &ranges[start_ix..] {
20587                if range
20588                    .start
20589                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20590                    .is_ge()
20591                {
20592                    break;
20593                }
20594
20595                let start = range.start.to_display_point(display_snapshot);
20596                let end = range.end.to_display_point(display_snapshot);
20597                results.push((start..end, color))
20598            }
20599        }
20600        results
20601    }
20602
20603    pub fn gutter_highlights_in_range(
20604        &self,
20605        search_range: Range<Anchor>,
20606        display_snapshot: &DisplaySnapshot,
20607        cx: &App,
20608    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20609        let mut results = Vec::new();
20610        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20611            let color = color_fetcher(cx);
20612            let start_ix = match ranges.binary_search_by(|probe| {
20613                let cmp = probe
20614                    .end
20615                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20616                if cmp.is_gt() {
20617                    Ordering::Greater
20618                } else {
20619                    Ordering::Less
20620                }
20621            }) {
20622                Ok(i) | Err(i) => i,
20623            };
20624            for range in &ranges[start_ix..] {
20625                if range
20626                    .start
20627                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20628                    .is_ge()
20629                {
20630                    break;
20631                }
20632
20633                let start = range.start.to_display_point(display_snapshot);
20634                let end = range.end.to_display_point(display_snapshot);
20635                results.push((start..end, color))
20636            }
20637        }
20638        results
20639    }
20640
20641    /// Get the text ranges corresponding to the redaction query
20642    pub fn redacted_ranges(
20643        &self,
20644        search_range: Range<Anchor>,
20645        display_snapshot: &DisplaySnapshot,
20646        cx: &App,
20647    ) -> Vec<Range<DisplayPoint>> {
20648        display_snapshot
20649            .buffer_snapshot()
20650            .redacted_ranges(search_range, |file| {
20651                if let Some(file) = file {
20652                    file.is_private()
20653                        && EditorSettings::get(
20654                            Some(SettingsLocation {
20655                                worktree_id: file.worktree_id(cx),
20656                                path: file.path().as_ref(),
20657                            }),
20658                            cx,
20659                        )
20660                        .redact_private_values
20661                } else {
20662                    false
20663                }
20664            })
20665            .map(|range| {
20666                range.start.to_display_point(display_snapshot)
20667                    ..range.end.to_display_point(display_snapshot)
20668            })
20669            .collect()
20670    }
20671
20672    pub fn highlight_text_key<T: 'static>(
20673        &mut self,
20674        key: usize,
20675        ranges: Vec<Range<Anchor>>,
20676        style: HighlightStyle,
20677        cx: &mut Context<Self>,
20678    ) {
20679        self.display_map.update(cx, |map, _| {
20680            map.highlight_text(
20681                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20682                ranges,
20683                style,
20684            );
20685        });
20686        cx.notify();
20687    }
20688
20689    pub fn highlight_text<T: 'static>(
20690        &mut self,
20691        ranges: Vec<Range<Anchor>>,
20692        style: HighlightStyle,
20693        cx: &mut Context<Self>,
20694    ) {
20695        self.display_map.update(cx, |map, _| {
20696            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20697        });
20698        cx.notify();
20699    }
20700
20701    pub(crate) fn highlight_inlays<T: 'static>(
20702        &mut self,
20703        highlights: Vec<InlayHighlight>,
20704        style: HighlightStyle,
20705        cx: &mut Context<Self>,
20706    ) {
20707        self.display_map.update(cx, |map, _| {
20708            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20709        });
20710        cx.notify();
20711    }
20712
20713    pub fn text_highlights<'a, T: 'static>(
20714        &'a self,
20715        cx: &'a App,
20716    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20717        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20718    }
20719
20720    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20721        let cleared = self
20722            .display_map
20723            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20724        if cleared {
20725            cx.notify();
20726        }
20727    }
20728
20729    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20730        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20731            && self.focus_handle.is_focused(window)
20732    }
20733
20734    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20735        self.show_cursor_when_unfocused = is_enabled;
20736        cx.notify();
20737    }
20738
20739    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20740        cx.notify();
20741    }
20742
20743    fn on_debug_session_event(
20744        &mut self,
20745        _session: Entity<Session>,
20746        event: &SessionEvent,
20747        cx: &mut Context<Self>,
20748    ) {
20749        if let SessionEvent::InvalidateInlineValue = event {
20750            self.refresh_inline_values(cx);
20751        }
20752    }
20753
20754    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20755        let Some(project) = self.project.clone() else {
20756            return;
20757        };
20758
20759        if !self.inline_value_cache.enabled {
20760            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20761            self.splice_inlays(&inlays, Vec::new(), cx);
20762            return;
20763        }
20764
20765        let current_execution_position = self
20766            .highlighted_rows
20767            .get(&TypeId::of::<ActiveDebugLine>())
20768            .and_then(|lines| lines.last().map(|line| line.range.end));
20769
20770        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20771            let inline_values = editor
20772                .update(cx, |editor, cx| {
20773                    let Some(current_execution_position) = current_execution_position else {
20774                        return Some(Task::ready(Ok(Vec::new())));
20775                    };
20776
20777                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20778                        let snapshot = buffer.snapshot(cx);
20779
20780                        let excerpt = snapshot.excerpt_containing(
20781                            current_execution_position..current_execution_position,
20782                        )?;
20783
20784                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20785                    })?;
20786
20787                    let range =
20788                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20789
20790                    project.inline_values(buffer, range, cx)
20791                })
20792                .ok()
20793                .flatten()?
20794                .await
20795                .context("refreshing debugger inlays")
20796                .log_err()?;
20797
20798            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20799
20800            for (buffer_id, inline_value) in inline_values
20801                .into_iter()
20802                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20803            {
20804                buffer_inline_values
20805                    .entry(buffer_id)
20806                    .or_default()
20807                    .push(inline_value);
20808            }
20809
20810            editor
20811                .update(cx, |editor, cx| {
20812                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20813                    let mut new_inlays = Vec::default();
20814
20815                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20816                        let buffer_id = buffer_snapshot.remote_id();
20817                        buffer_inline_values
20818                            .get(&buffer_id)
20819                            .into_iter()
20820                            .flatten()
20821                            .for_each(|hint| {
20822                                let inlay = Inlay::debugger(
20823                                    post_inc(&mut editor.next_inlay_id),
20824                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20825                                    hint.text(),
20826                                );
20827                                if !inlay.text().chars().contains(&'\n') {
20828                                    new_inlays.push(inlay);
20829                                }
20830                            });
20831                    }
20832
20833                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20834                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20835
20836                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20837                })
20838                .ok()?;
20839            Some(())
20840        });
20841    }
20842
20843    fn on_buffer_event(
20844        &mut self,
20845        multibuffer: &Entity<MultiBuffer>,
20846        event: &multi_buffer::Event,
20847        window: &mut Window,
20848        cx: &mut Context<Self>,
20849    ) {
20850        match event {
20851            multi_buffer::Event::Edited {
20852                singleton_buffer_edited,
20853                edited_buffer,
20854            } => {
20855                self.scrollbar_marker_state.dirty = true;
20856                self.active_indent_guides_state.dirty = true;
20857                self.refresh_active_diagnostics(cx);
20858                self.refresh_code_actions(window, cx);
20859                self.refresh_selected_text_highlights(true, window, cx);
20860                self.refresh_single_line_folds(window, cx);
20861                refresh_matching_bracket_highlights(self, cx);
20862                if self.has_active_edit_prediction() {
20863                    self.update_visible_edit_prediction(window, cx);
20864                }
20865                if let Some(project) = self.project.as_ref()
20866                    && let Some(edited_buffer) = edited_buffer
20867                {
20868                    project.update(cx, |project, cx| {
20869                        self.registered_buffers
20870                            .entry(edited_buffer.read(cx).remote_id())
20871                            .or_insert_with(|| {
20872                                project.register_buffer_with_language_servers(edited_buffer, cx)
20873                            });
20874                    });
20875                }
20876                cx.emit(EditorEvent::BufferEdited);
20877                cx.emit(SearchEvent::MatchesInvalidated);
20878
20879                if let Some(buffer) = edited_buffer {
20880                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20881                }
20882
20883                if *singleton_buffer_edited {
20884                    if let Some(buffer) = edited_buffer
20885                        && buffer.read(cx).file().is_none()
20886                    {
20887                        cx.emit(EditorEvent::TitleChanged);
20888                    }
20889                    if let Some(project) = &self.project {
20890                        #[allow(clippy::mutable_key_type)]
20891                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20892                            multibuffer
20893                                .all_buffers()
20894                                .into_iter()
20895                                .filter_map(|buffer| {
20896                                    buffer.update(cx, |buffer, cx| {
20897                                        let language = buffer.language()?;
20898                                        let should_discard = project.update(cx, |project, cx| {
20899                                            project.is_local()
20900                                                && !project.has_language_servers_for(buffer, cx)
20901                                        });
20902                                        should_discard.not().then_some(language.clone())
20903                                    })
20904                                })
20905                                .collect::<HashSet<_>>()
20906                        });
20907                        if !languages_affected.is_empty() {
20908                            self.refresh_inlay_hints(
20909                                InlayHintRefreshReason::BufferEdited(languages_affected),
20910                                cx,
20911                            );
20912                        }
20913                    }
20914                }
20915
20916                let Some(project) = &self.project else { return };
20917                let (telemetry, is_via_ssh) = {
20918                    let project = project.read(cx);
20919                    let telemetry = project.client().telemetry().clone();
20920                    let is_via_ssh = project.is_via_remote_server();
20921                    (telemetry, is_via_ssh)
20922                };
20923                refresh_linked_ranges(self, window, cx);
20924                telemetry.log_edit_event("editor", is_via_ssh);
20925            }
20926            multi_buffer::Event::ExcerptsAdded {
20927                buffer,
20928                predecessor,
20929                excerpts,
20930            } => {
20931                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20932                let buffer_id = buffer.read(cx).remote_id();
20933                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20934                    && let Some(project) = &self.project
20935                {
20936                    update_uncommitted_diff_for_buffer(
20937                        cx.entity(),
20938                        project,
20939                        [buffer.clone()],
20940                        self.buffer.clone(),
20941                        cx,
20942                    )
20943                    .detach();
20944                }
20945                if self.active_diagnostics != ActiveDiagnostic::All {
20946                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20947                }
20948                cx.emit(EditorEvent::ExcerptsAdded {
20949                    buffer: buffer.clone(),
20950                    predecessor: *predecessor,
20951                    excerpts: excerpts.clone(),
20952                });
20953                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20954            }
20955            multi_buffer::Event::ExcerptsRemoved {
20956                ids,
20957                removed_buffer_ids,
20958            } => {
20959                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20960                let buffer = self.buffer.read(cx);
20961                self.registered_buffers
20962                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20963                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20964                cx.emit(EditorEvent::ExcerptsRemoved {
20965                    ids: ids.clone(),
20966                    removed_buffer_ids: removed_buffer_ids.clone(),
20967                });
20968            }
20969            multi_buffer::Event::ExcerptsEdited {
20970                excerpt_ids,
20971                buffer_ids,
20972            } => {
20973                self.display_map.update(cx, |map, cx| {
20974                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20975                });
20976                cx.emit(EditorEvent::ExcerptsEdited {
20977                    ids: excerpt_ids.clone(),
20978                });
20979            }
20980            multi_buffer::Event::ExcerptsExpanded { ids } => {
20981                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20982                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20983            }
20984            multi_buffer::Event::Reparsed(buffer_id) => {
20985                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20986                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20987
20988                cx.emit(EditorEvent::Reparsed(*buffer_id));
20989            }
20990            multi_buffer::Event::DiffHunksToggled => {
20991                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20992            }
20993            multi_buffer::Event::LanguageChanged(buffer_id) => {
20994                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20995                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20996                cx.emit(EditorEvent::Reparsed(*buffer_id));
20997                cx.notify();
20998            }
20999            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21000            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21001            multi_buffer::Event::FileHandleChanged
21002            | multi_buffer::Event::Reloaded
21003            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21004            multi_buffer::Event::DiagnosticsUpdated => {
21005                self.update_diagnostics_state(window, cx);
21006            }
21007            _ => {}
21008        };
21009    }
21010
21011    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21012        if !self.diagnostics_enabled() {
21013            return;
21014        }
21015        self.refresh_active_diagnostics(cx);
21016        self.refresh_inline_diagnostics(true, window, cx);
21017        self.scrollbar_marker_state.dirty = true;
21018        cx.notify();
21019    }
21020
21021    pub fn start_temporary_diff_override(&mut self) {
21022        self.load_diff_task.take();
21023        self.temporary_diff_override = true;
21024    }
21025
21026    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21027        self.temporary_diff_override = false;
21028        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21029        self.buffer.update(cx, |buffer, cx| {
21030            buffer.set_all_diff_hunks_collapsed(cx);
21031        });
21032
21033        if let Some(project) = self.project.clone() {
21034            self.load_diff_task = Some(
21035                update_uncommitted_diff_for_buffer(
21036                    cx.entity(),
21037                    &project,
21038                    self.buffer.read(cx).all_buffers(),
21039                    self.buffer.clone(),
21040                    cx,
21041                )
21042                .shared(),
21043            );
21044        }
21045    }
21046
21047    fn on_display_map_changed(
21048        &mut self,
21049        _: Entity<DisplayMap>,
21050        _: &mut Window,
21051        cx: &mut Context<Self>,
21052    ) {
21053        cx.notify();
21054    }
21055
21056    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21057        if self.diagnostics_enabled() {
21058            let new_severity = EditorSettings::get_global(cx)
21059                .diagnostics_max_severity
21060                .unwrap_or(DiagnosticSeverity::Hint);
21061            self.set_max_diagnostics_severity(new_severity, cx);
21062        }
21063        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21064        self.update_edit_prediction_settings(cx);
21065        self.refresh_edit_prediction(true, false, window, cx);
21066        self.refresh_inline_values(cx);
21067        self.refresh_inlay_hints(
21068            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21069                self.selections.newest_anchor().head(),
21070                &self.buffer.read(cx).snapshot(cx),
21071                cx,
21072            )),
21073            cx,
21074        );
21075
21076        let old_cursor_shape = self.cursor_shape;
21077        let old_show_breadcrumbs = self.show_breadcrumbs;
21078
21079        {
21080            let editor_settings = EditorSettings::get_global(cx);
21081            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21082            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21083            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21084            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21085        }
21086
21087        if old_cursor_shape != self.cursor_shape {
21088            cx.emit(EditorEvent::CursorShapeChanged);
21089        }
21090
21091        if old_show_breadcrumbs != self.show_breadcrumbs {
21092            cx.emit(EditorEvent::BreadcrumbsChanged);
21093        }
21094
21095        let project_settings = ProjectSettings::get_global(cx);
21096        self.serialize_dirty_buffers =
21097            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21098
21099        if self.mode.is_full() {
21100            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21101            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21102            if self.show_inline_diagnostics != show_inline_diagnostics {
21103                self.show_inline_diagnostics = show_inline_diagnostics;
21104                self.refresh_inline_diagnostics(false, window, cx);
21105            }
21106
21107            if self.git_blame_inline_enabled != inline_blame_enabled {
21108                self.toggle_git_blame_inline_internal(false, window, cx);
21109            }
21110
21111            let minimap_settings = EditorSettings::get_global(cx).minimap;
21112            if self.minimap_visibility != MinimapVisibility::Disabled {
21113                if self.minimap_visibility.settings_visibility()
21114                    != minimap_settings.minimap_enabled()
21115                {
21116                    self.set_minimap_visibility(
21117                        MinimapVisibility::for_mode(self.mode(), cx),
21118                        window,
21119                        cx,
21120                    );
21121                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21122                    minimap_entity.update(cx, |minimap_editor, cx| {
21123                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21124                    })
21125                }
21126            }
21127        }
21128
21129        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21130            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21131        }) {
21132            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21133                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21134            }
21135            self.refresh_colors(false, None, window, cx);
21136        }
21137
21138        cx.notify();
21139    }
21140
21141    pub fn set_searchable(&mut self, searchable: bool) {
21142        self.searchable = searchable;
21143    }
21144
21145    pub fn searchable(&self) -> bool {
21146        self.searchable
21147    }
21148
21149    fn open_proposed_changes_editor(
21150        &mut self,
21151        _: &OpenProposedChangesEditor,
21152        window: &mut Window,
21153        cx: &mut Context<Self>,
21154    ) {
21155        let Some(workspace) = self.workspace() else {
21156            cx.propagate();
21157            return;
21158        };
21159
21160        let selections = self.selections.all::<usize>(cx);
21161        let multi_buffer = self.buffer.read(cx);
21162        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21163        let mut new_selections_by_buffer = HashMap::default();
21164        for selection in selections {
21165            for (buffer, range, _) in
21166                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21167            {
21168                let mut range = range.to_point(buffer);
21169                range.start.column = 0;
21170                range.end.column = buffer.line_len(range.end.row);
21171                new_selections_by_buffer
21172                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21173                    .or_insert(Vec::new())
21174                    .push(range)
21175            }
21176        }
21177
21178        let proposed_changes_buffers = new_selections_by_buffer
21179            .into_iter()
21180            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21181            .collect::<Vec<_>>();
21182        let proposed_changes_editor = cx.new(|cx| {
21183            ProposedChangesEditor::new(
21184                "Proposed changes",
21185                proposed_changes_buffers,
21186                self.project.clone(),
21187                window,
21188                cx,
21189            )
21190        });
21191
21192        window.defer(cx, move |window, cx| {
21193            workspace.update(cx, |workspace, cx| {
21194                workspace.active_pane().update(cx, |pane, cx| {
21195                    pane.add_item(
21196                        Box::new(proposed_changes_editor),
21197                        true,
21198                        true,
21199                        None,
21200                        window,
21201                        cx,
21202                    );
21203                });
21204            });
21205        });
21206    }
21207
21208    pub fn open_excerpts_in_split(
21209        &mut self,
21210        _: &OpenExcerptsSplit,
21211        window: &mut Window,
21212        cx: &mut Context<Self>,
21213    ) {
21214        self.open_excerpts_common(None, true, window, cx)
21215    }
21216
21217    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21218        self.open_excerpts_common(None, false, window, cx)
21219    }
21220
21221    fn open_excerpts_common(
21222        &mut self,
21223        jump_data: Option<JumpData>,
21224        split: bool,
21225        window: &mut Window,
21226        cx: &mut Context<Self>,
21227    ) {
21228        let Some(workspace) = self.workspace() else {
21229            cx.propagate();
21230            return;
21231        };
21232
21233        if self.buffer.read(cx).is_singleton() {
21234            cx.propagate();
21235            return;
21236        }
21237
21238        let mut new_selections_by_buffer = HashMap::default();
21239        match &jump_data {
21240            Some(JumpData::MultiBufferPoint {
21241                excerpt_id,
21242                position,
21243                anchor,
21244                line_offset_from_top,
21245            }) => {
21246                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21247                if let Some(buffer) = multi_buffer_snapshot
21248                    .buffer_id_for_excerpt(*excerpt_id)
21249                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21250                {
21251                    let buffer_snapshot = buffer.read(cx).snapshot();
21252                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21253                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21254                    } else {
21255                        buffer_snapshot.clip_point(*position, Bias::Left)
21256                    };
21257                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21258                    new_selections_by_buffer.insert(
21259                        buffer,
21260                        (
21261                            vec![jump_to_offset..jump_to_offset],
21262                            Some(*line_offset_from_top),
21263                        ),
21264                    );
21265                }
21266            }
21267            Some(JumpData::MultiBufferRow {
21268                row,
21269                line_offset_from_top,
21270            }) => {
21271                let point = MultiBufferPoint::new(row.0, 0);
21272                if let Some((buffer, buffer_point, _)) =
21273                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21274                {
21275                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21276                    new_selections_by_buffer
21277                        .entry(buffer)
21278                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21279                        .0
21280                        .push(buffer_offset..buffer_offset)
21281                }
21282            }
21283            None => {
21284                let selections = self.selections.all::<usize>(cx);
21285                let multi_buffer = self.buffer.read(cx);
21286                for selection in selections {
21287                    for (snapshot, range, _, anchor) in multi_buffer
21288                        .snapshot(cx)
21289                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21290                    {
21291                        if let Some(anchor) = anchor {
21292                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21293                            else {
21294                                continue;
21295                            };
21296                            let offset = text::ToOffset::to_offset(
21297                                &anchor.text_anchor,
21298                                &buffer_handle.read(cx).snapshot(),
21299                            );
21300                            let range = offset..offset;
21301                            new_selections_by_buffer
21302                                .entry(buffer_handle)
21303                                .or_insert((Vec::new(), None))
21304                                .0
21305                                .push(range)
21306                        } else {
21307                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21308                            else {
21309                                continue;
21310                            };
21311                            new_selections_by_buffer
21312                                .entry(buffer_handle)
21313                                .or_insert((Vec::new(), None))
21314                                .0
21315                                .push(range)
21316                        }
21317                    }
21318                }
21319            }
21320        }
21321
21322        new_selections_by_buffer
21323            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21324
21325        if new_selections_by_buffer.is_empty() {
21326            return;
21327        }
21328
21329        // We defer the pane interaction because we ourselves are a workspace item
21330        // and activating a new item causes the pane to call a method on us reentrantly,
21331        // which panics if we're on the stack.
21332        window.defer(cx, move |window, cx| {
21333            workspace.update(cx, |workspace, cx| {
21334                let pane = if split {
21335                    workspace.adjacent_pane(window, cx)
21336                } else {
21337                    workspace.active_pane().clone()
21338                };
21339
21340                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21341                    let editor = buffer
21342                        .read(cx)
21343                        .file()
21344                        .is_none()
21345                        .then(|| {
21346                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21347                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21348                            // Instead, we try to activate the existing editor in the pane first.
21349                            let (editor, pane_item_index) =
21350                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21351                                    let editor = item.downcast::<Editor>()?;
21352                                    let singleton_buffer =
21353                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21354                                    if singleton_buffer == buffer {
21355                                        Some((editor, i))
21356                                    } else {
21357                                        None
21358                                    }
21359                                })?;
21360                            pane.update(cx, |pane, cx| {
21361                                pane.activate_item(pane_item_index, true, true, window, cx)
21362                            });
21363                            Some(editor)
21364                        })
21365                        .flatten()
21366                        .unwrap_or_else(|| {
21367                            workspace.open_project_item::<Self>(
21368                                pane.clone(),
21369                                buffer,
21370                                true,
21371                                true,
21372                                window,
21373                                cx,
21374                            )
21375                        });
21376
21377                    editor.update(cx, |editor, cx| {
21378                        let autoscroll = match scroll_offset {
21379                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21380                            None => Autoscroll::newest(),
21381                        };
21382                        let nav_history = editor.nav_history.take();
21383                        editor.change_selections(
21384                            SelectionEffects::scroll(autoscroll),
21385                            window,
21386                            cx,
21387                            |s| {
21388                                s.select_ranges(ranges);
21389                            },
21390                        );
21391                        editor.nav_history = nav_history;
21392                    });
21393                }
21394            })
21395        });
21396    }
21397
21398    // For now, don't allow opening excerpts in buffers that aren't backed by
21399    // regular project files.
21400    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21401        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21402    }
21403
21404    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21405        let snapshot = self.buffer.read(cx).read(cx);
21406        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21407        Some(
21408            ranges
21409                .iter()
21410                .map(move |range| {
21411                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21412                })
21413                .collect(),
21414        )
21415    }
21416
21417    fn selection_replacement_ranges(
21418        &self,
21419        range: Range<OffsetUtf16>,
21420        cx: &mut App,
21421    ) -> Vec<Range<OffsetUtf16>> {
21422        let selections = self.selections.all::<OffsetUtf16>(cx);
21423        let newest_selection = selections
21424            .iter()
21425            .max_by_key(|selection| selection.id)
21426            .unwrap();
21427        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21428        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21429        let snapshot = self.buffer.read(cx).read(cx);
21430        selections
21431            .into_iter()
21432            .map(|mut selection| {
21433                selection.start.0 =
21434                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21435                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21436                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21437                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21438            })
21439            .collect()
21440    }
21441
21442    fn report_editor_event(
21443        &self,
21444        reported_event: ReportEditorEvent,
21445        file_extension: Option<String>,
21446        cx: &App,
21447    ) {
21448        if cfg!(any(test, feature = "test-support")) {
21449            return;
21450        }
21451
21452        let Some(project) = &self.project else { return };
21453
21454        // If None, we are in a file without an extension
21455        let file = self
21456            .buffer
21457            .read(cx)
21458            .as_singleton()
21459            .and_then(|b| b.read(cx).file());
21460        let file_extension = file_extension.or(file
21461            .as_ref()
21462            .and_then(|file| Path::new(file.file_name(cx)).extension())
21463            .and_then(|e| e.to_str())
21464            .map(|a| a.to_string()));
21465
21466        let vim_mode = vim_enabled(cx);
21467
21468        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21469        let copilot_enabled = edit_predictions_provider
21470            == language::language_settings::EditPredictionProvider::Copilot;
21471        let copilot_enabled_for_language = self
21472            .buffer
21473            .read(cx)
21474            .language_settings(cx)
21475            .show_edit_predictions;
21476
21477        let project = project.read(cx);
21478        let event_type = reported_event.event_type();
21479
21480        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21481            telemetry::event!(
21482                event_type,
21483                type = if auto_saved {"autosave"} else {"manual"},
21484                file_extension,
21485                vim_mode,
21486                copilot_enabled,
21487                copilot_enabled_for_language,
21488                edit_predictions_provider,
21489                is_via_ssh = project.is_via_remote_server(),
21490            );
21491        } else {
21492            telemetry::event!(
21493                event_type,
21494                file_extension,
21495                vim_mode,
21496                copilot_enabled,
21497                copilot_enabled_for_language,
21498                edit_predictions_provider,
21499                is_via_ssh = project.is_via_remote_server(),
21500            );
21501        };
21502    }
21503
21504    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21505    /// with each line being an array of {text, highlight} objects.
21506    fn copy_highlight_json(
21507        &mut self,
21508        _: &CopyHighlightJson,
21509        window: &mut Window,
21510        cx: &mut Context<Self>,
21511    ) {
21512        #[derive(Serialize)]
21513        struct Chunk<'a> {
21514            text: String,
21515            highlight: Option<&'a str>,
21516        }
21517
21518        let snapshot = self.buffer.read(cx).snapshot(cx);
21519        let range = self
21520            .selected_text_range(false, window, cx)
21521            .and_then(|selection| {
21522                if selection.range.is_empty() {
21523                    None
21524                } else {
21525                    Some(selection.range)
21526                }
21527            })
21528            .unwrap_or_else(|| 0..snapshot.len());
21529
21530        let chunks = snapshot.chunks(range, true);
21531        let mut lines = Vec::new();
21532        let mut line: VecDeque<Chunk> = VecDeque::new();
21533
21534        let Some(style) = self.style.as_ref() else {
21535            return;
21536        };
21537
21538        for chunk in chunks {
21539            let highlight = chunk
21540                .syntax_highlight_id
21541                .and_then(|id| id.name(&style.syntax));
21542            let mut chunk_lines = chunk.text.split('\n').peekable();
21543            while let Some(text) = chunk_lines.next() {
21544                let mut merged_with_last_token = false;
21545                if let Some(last_token) = line.back_mut()
21546                    && last_token.highlight == highlight
21547                {
21548                    last_token.text.push_str(text);
21549                    merged_with_last_token = true;
21550                }
21551
21552                if !merged_with_last_token {
21553                    line.push_back(Chunk {
21554                        text: text.into(),
21555                        highlight,
21556                    });
21557                }
21558
21559                if chunk_lines.peek().is_some() {
21560                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21561                        line.pop_front();
21562                    }
21563                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21564                        line.pop_back();
21565                    }
21566
21567                    lines.push(mem::take(&mut line));
21568                }
21569            }
21570        }
21571
21572        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21573            return;
21574        };
21575        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21576    }
21577
21578    pub fn open_context_menu(
21579        &mut self,
21580        _: &OpenContextMenu,
21581        window: &mut Window,
21582        cx: &mut Context<Self>,
21583    ) {
21584        self.request_autoscroll(Autoscroll::newest(), cx);
21585        let position = self.selections.newest_display(cx).start;
21586        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21587    }
21588
21589    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21590        &self.inlay_hint_cache
21591    }
21592
21593    pub fn replay_insert_event(
21594        &mut self,
21595        text: &str,
21596        relative_utf16_range: Option<Range<isize>>,
21597        window: &mut Window,
21598        cx: &mut Context<Self>,
21599    ) {
21600        if !self.input_enabled {
21601            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21602            return;
21603        }
21604        if let Some(relative_utf16_range) = relative_utf16_range {
21605            let selections = self.selections.all::<OffsetUtf16>(cx);
21606            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21607                let new_ranges = selections.into_iter().map(|range| {
21608                    let start = OffsetUtf16(
21609                        range
21610                            .head()
21611                            .0
21612                            .saturating_add_signed(relative_utf16_range.start),
21613                    );
21614                    let end = OffsetUtf16(
21615                        range
21616                            .head()
21617                            .0
21618                            .saturating_add_signed(relative_utf16_range.end),
21619                    );
21620                    start..end
21621                });
21622                s.select_ranges(new_ranges);
21623            });
21624        }
21625
21626        self.handle_input(text, window, cx);
21627    }
21628
21629    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21630        let Some(provider) = self.semantics_provider.as_ref() else {
21631            return false;
21632        };
21633
21634        let mut supports = false;
21635        self.buffer().update(cx, |this, cx| {
21636            this.for_each_buffer(|buffer| {
21637                supports |= provider.supports_inlay_hints(buffer, cx);
21638            });
21639        });
21640
21641        supports
21642    }
21643
21644    pub fn is_focused(&self, window: &Window) -> bool {
21645        self.focus_handle.is_focused(window)
21646    }
21647
21648    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21649        cx.emit(EditorEvent::Focused);
21650
21651        if let Some(descendant) = self
21652            .last_focused_descendant
21653            .take()
21654            .and_then(|descendant| descendant.upgrade())
21655        {
21656            window.focus(&descendant);
21657        } else {
21658            if let Some(blame) = self.blame.as_ref() {
21659                blame.update(cx, GitBlame::focus)
21660            }
21661
21662            self.blink_manager.update(cx, BlinkManager::enable);
21663            self.show_cursor_names(window, cx);
21664            self.buffer.update(cx, |buffer, cx| {
21665                buffer.finalize_last_transaction(cx);
21666                if self.leader_id.is_none() {
21667                    buffer.set_active_selections(
21668                        &self.selections.disjoint_anchors_arc(),
21669                        self.selections.line_mode(),
21670                        self.cursor_shape,
21671                        cx,
21672                    );
21673                }
21674            });
21675        }
21676    }
21677
21678    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21679        cx.emit(EditorEvent::FocusedIn)
21680    }
21681
21682    fn handle_focus_out(
21683        &mut self,
21684        event: FocusOutEvent,
21685        _window: &mut Window,
21686        cx: &mut Context<Self>,
21687    ) {
21688        if event.blurred != self.focus_handle {
21689            self.last_focused_descendant = Some(event.blurred);
21690        }
21691        self.selection_drag_state = SelectionDragState::None;
21692        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21693    }
21694
21695    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21696        self.blink_manager.update(cx, BlinkManager::disable);
21697        self.buffer
21698            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21699
21700        if let Some(blame) = self.blame.as_ref() {
21701            blame.update(cx, GitBlame::blur)
21702        }
21703        if !self.hover_state.focused(window, cx) {
21704            hide_hover(self, cx);
21705        }
21706        if !self
21707            .context_menu
21708            .borrow()
21709            .as_ref()
21710            .is_some_and(|context_menu| context_menu.focused(window, cx))
21711        {
21712            self.hide_context_menu(window, cx);
21713        }
21714        self.take_active_edit_prediction(cx);
21715        cx.emit(EditorEvent::Blurred);
21716        cx.notify();
21717    }
21718
21719    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21720        let mut pending: String = window
21721            .pending_input_keystrokes()
21722            .into_iter()
21723            .flatten()
21724            .filter_map(|keystroke| {
21725                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21726                    keystroke.key_char.clone()
21727                } else {
21728                    None
21729                }
21730            })
21731            .collect();
21732
21733        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21734            pending = "".to_string();
21735        }
21736
21737        let existing_pending = self
21738            .text_highlights::<PendingInput>(cx)
21739            .map(|(_, ranges)| ranges.to_vec());
21740        if existing_pending.is_none() && pending.is_empty() {
21741            return;
21742        }
21743        let transaction =
21744            self.transact(window, cx, |this, window, cx| {
21745                let selections = this.selections.all::<usize>(cx);
21746                let edits = selections
21747                    .iter()
21748                    .map(|selection| (selection.end..selection.end, pending.clone()));
21749                this.edit(edits, cx);
21750                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21751                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21752                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21753                    }));
21754                });
21755                if let Some(existing_ranges) = existing_pending {
21756                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21757                    this.edit(edits, cx);
21758                }
21759            });
21760
21761        let snapshot = self.snapshot(window, cx);
21762        let ranges = self
21763            .selections
21764            .all::<usize>(cx)
21765            .into_iter()
21766            .map(|selection| {
21767                snapshot.buffer_snapshot().anchor_after(selection.end)
21768                    ..snapshot
21769                        .buffer_snapshot()
21770                        .anchor_before(selection.end + pending.len())
21771            })
21772            .collect();
21773
21774        if pending.is_empty() {
21775            self.clear_highlights::<PendingInput>(cx);
21776        } else {
21777            self.highlight_text::<PendingInput>(
21778                ranges,
21779                HighlightStyle {
21780                    underline: Some(UnderlineStyle {
21781                        thickness: px(1.),
21782                        color: None,
21783                        wavy: false,
21784                    }),
21785                    ..Default::default()
21786                },
21787                cx,
21788            );
21789        }
21790
21791        self.ime_transaction = self.ime_transaction.or(transaction);
21792        if let Some(transaction) = self.ime_transaction {
21793            self.buffer.update(cx, |buffer, cx| {
21794                buffer.group_until_transaction(transaction, cx);
21795            });
21796        }
21797
21798        if self.text_highlights::<PendingInput>(cx).is_none() {
21799            self.ime_transaction.take();
21800        }
21801    }
21802
21803    pub fn register_action_renderer(
21804        &mut self,
21805        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21806    ) -> Subscription {
21807        let id = self.next_editor_action_id.post_inc();
21808        self.editor_actions
21809            .borrow_mut()
21810            .insert(id, Box::new(listener));
21811
21812        let editor_actions = self.editor_actions.clone();
21813        Subscription::new(move || {
21814            editor_actions.borrow_mut().remove(&id);
21815        })
21816    }
21817
21818    pub fn register_action<A: Action>(
21819        &mut self,
21820        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21821    ) -> Subscription {
21822        let id = self.next_editor_action_id.post_inc();
21823        let listener = Arc::new(listener);
21824        self.editor_actions.borrow_mut().insert(
21825            id,
21826            Box::new(move |_, window, _| {
21827                let listener = listener.clone();
21828                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21829                    let action = action.downcast_ref().unwrap();
21830                    if phase == DispatchPhase::Bubble {
21831                        listener(action, window, cx)
21832                    }
21833                })
21834            }),
21835        );
21836
21837        let editor_actions = self.editor_actions.clone();
21838        Subscription::new(move || {
21839            editor_actions.borrow_mut().remove(&id);
21840        })
21841    }
21842
21843    pub fn file_header_size(&self) -> u32 {
21844        FILE_HEADER_HEIGHT
21845    }
21846
21847    pub fn restore(
21848        &mut self,
21849        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21850        window: &mut Window,
21851        cx: &mut Context<Self>,
21852    ) {
21853        let workspace = self.workspace();
21854        let project = self.project();
21855        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21856            let mut tasks = Vec::new();
21857            for (buffer_id, changes) in revert_changes {
21858                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21859                    buffer.update(cx, |buffer, cx| {
21860                        buffer.edit(
21861                            changes
21862                                .into_iter()
21863                                .map(|(range, text)| (range, text.to_string())),
21864                            None,
21865                            cx,
21866                        );
21867                    });
21868
21869                    if let Some(project) =
21870                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21871                    {
21872                        project.update(cx, |project, cx| {
21873                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21874                        })
21875                    }
21876                }
21877            }
21878            tasks
21879        });
21880        cx.spawn_in(window, async move |_, cx| {
21881            for (buffer, task) in save_tasks {
21882                let result = task.await;
21883                if result.is_err() {
21884                    let Some(path) = buffer
21885                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21886                        .ok()
21887                    else {
21888                        continue;
21889                    };
21890                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21891                        let Some(task) = cx
21892                            .update_window_entity(workspace, |workspace, window, cx| {
21893                                workspace
21894                                    .open_path_preview(path, None, false, false, false, window, cx)
21895                            })
21896                            .ok()
21897                        else {
21898                            continue;
21899                        };
21900                        task.await.log_err();
21901                    }
21902                }
21903            }
21904        })
21905        .detach();
21906        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21907            selections.refresh()
21908        });
21909    }
21910
21911    pub fn to_pixel_point(
21912        &self,
21913        source: multi_buffer::Anchor,
21914        editor_snapshot: &EditorSnapshot,
21915        window: &mut Window,
21916    ) -> Option<gpui::Point<Pixels>> {
21917        let source_point = source.to_display_point(editor_snapshot);
21918        self.display_to_pixel_point(source_point, editor_snapshot, window)
21919    }
21920
21921    pub fn display_to_pixel_point(
21922        &self,
21923        source: DisplayPoint,
21924        editor_snapshot: &EditorSnapshot,
21925        window: &mut Window,
21926    ) -> Option<gpui::Point<Pixels>> {
21927        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21928        let text_layout_details = self.text_layout_details(window);
21929        let scroll_top = text_layout_details
21930            .scroll_anchor
21931            .scroll_position(editor_snapshot)
21932            .y;
21933
21934        if source.row().as_f64() < scroll_top.floor() {
21935            return None;
21936        }
21937        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21938        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21939        Some(gpui::Point::new(source_x, source_y))
21940    }
21941
21942    pub fn has_visible_completions_menu(&self) -> bool {
21943        !self.edit_prediction_preview_is_active()
21944            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21945                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21946            })
21947    }
21948
21949    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21950        if self.mode.is_minimap() {
21951            return;
21952        }
21953        self.addons
21954            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21955    }
21956
21957    pub fn unregister_addon<T: Addon>(&mut self) {
21958        self.addons.remove(&std::any::TypeId::of::<T>());
21959    }
21960
21961    pub fn addon<T: Addon>(&self) -> Option<&T> {
21962        let type_id = std::any::TypeId::of::<T>();
21963        self.addons
21964            .get(&type_id)
21965            .and_then(|item| item.to_any().downcast_ref::<T>())
21966    }
21967
21968    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21969        let type_id = std::any::TypeId::of::<T>();
21970        self.addons
21971            .get_mut(&type_id)
21972            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21973    }
21974
21975    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21976        let text_layout_details = self.text_layout_details(window);
21977        let style = &text_layout_details.editor_style;
21978        let font_id = window.text_system().resolve_font(&style.text.font());
21979        let font_size = style.text.font_size.to_pixels(window.rem_size());
21980        let line_height = style.text.line_height_in_pixels(window.rem_size());
21981        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21982        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21983
21984        CharacterDimensions {
21985            em_width,
21986            em_advance,
21987            line_height,
21988        }
21989    }
21990
21991    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21992        self.load_diff_task.clone()
21993    }
21994
21995    fn read_metadata_from_db(
21996        &mut self,
21997        item_id: u64,
21998        workspace_id: WorkspaceId,
21999        window: &mut Window,
22000        cx: &mut Context<Editor>,
22001    ) {
22002        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22003            && !self.mode.is_minimap()
22004            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22005        {
22006            let buffer_snapshot = OnceCell::new();
22007
22008            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22009                && !folds.is_empty()
22010            {
22011                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22012                self.fold_ranges(
22013                    folds
22014                        .into_iter()
22015                        .map(|(start, end)| {
22016                            snapshot.clip_offset(start, Bias::Left)
22017                                ..snapshot.clip_offset(end, Bias::Right)
22018                        })
22019                        .collect(),
22020                    false,
22021                    window,
22022                    cx,
22023                );
22024            }
22025
22026            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22027                && !selections.is_empty()
22028            {
22029                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22030                // skip adding the initial selection to selection history
22031                self.selection_history.mode = SelectionHistoryMode::Skipping;
22032                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22033                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22034                        snapshot.clip_offset(start, Bias::Left)
22035                            ..snapshot.clip_offset(end, Bias::Right)
22036                    }));
22037                });
22038                self.selection_history.mode = SelectionHistoryMode::Normal;
22039            };
22040        }
22041
22042        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22043    }
22044
22045    fn update_lsp_data(
22046        &mut self,
22047        ignore_cache: bool,
22048        for_buffer: Option<BufferId>,
22049        window: &mut Window,
22050        cx: &mut Context<'_, Self>,
22051    ) {
22052        self.pull_diagnostics(for_buffer, window, cx);
22053        self.refresh_colors(ignore_cache, for_buffer, window, cx);
22054    }
22055}
22056
22057fn edit_for_markdown_paste<'a>(
22058    buffer: &MultiBufferSnapshot,
22059    range: Range<usize>,
22060    to_insert: &'a str,
22061    url: Option<url::Url>,
22062) -> (Range<usize>, Cow<'a, str>) {
22063    if url.is_none() {
22064        return (range, Cow::Borrowed(to_insert));
22065    };
22066
22067    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22068
22069    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22070        Cow::Borrowed(to_insert)
22071    } else {
22072        Cow::Owned(format!("[{old_text}]({to_insert})"))
22073    };
22074    (range, new_text)
22075}
22076
22077fn vim_enabled(cx: &App) -> bool {
22078    vim_mode_setting::VimModeSetting::try_get(cx)
22079        .map(|vim_mode| vim_mode.0)
22080        .unwrap_or(false)
22081}
22082
22083fn process_completion_for_edit(
22084    completion: &Completion,
22085    intent: CompletionIntent,
22086    buffer: &Entity<Buffer>,
22087    cursor_position: &text::Anchor,
22088    cx: &mut Context<Editor>,
22089) -> CompletionEdit {
22090    let buffer = buffer.read(cx);
22091    let buffer_snapshot = buffer.snapshot();
22092    let (snippet, new_text) = if completion.is_snippet() {
22093        let mut snippet_source = completion.new_text.clone();
22094        // Workaround for typescript language server issues so that methods don't expand within
22095        // strings and functions with type expressions. The previous point is used because the query
22096        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22097        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22098        let previous_point = if previous_point.column > 0 {
22099            cursor_position.to_previous_offset(&buffer_snapshot)
22100        } else {
22101            cursor_position.to_offset(&buffer_snapshot)
22102        };
22103        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22104            && scope.prefers_label_for_snippet_in_completion()
22105            && let Some(label) = completion.label()
22106            && matches!(
22107                completion.kind(),
22108                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22109            )
22110        {
22111            snippet_source = label;
22112        }
22113        match Snippet::parse(&snippet_source).log_err() {
22114            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22115            None => (None, completion.new_text.clone()),
22116        }
22117    } else {
22118        (None, completion.new_text.clone())
22119    };
22120
22121    let mut range_to_replace = {
22122        let replace_range = &completion.replace_range;
22123        if let CompletionSource::Lsp {
22124            insert_range: Some(insert_range),
22125            ..
22126        } = &completion.source
22127        {
22128            debug_assert_eq!(
22129                insert_range.start, replace_range.start,
22130                "insert_range and replace_range should start at the same position"
22131            );
22132            debug_assert!(
22133                insert_range
22134                    .start
22135                    .cmp(cursor_position, &buffer_snapshot)
22136                    .is_le(),
22137                "insert_range should start before or at cursor position"
22138            );
22139            debug_assert!(
22140                replace_range
22141                    .start
22142                    .cmp(cursor_position, &buffer_snapshot)
22143                    .is_le(),
22144                "replace_range should start before or at cursor position"
22145            );
22146
22147            let should_replace = match intent {
22148                CompletionIntent::CompleteWithInsert => false,
22149                CompletionIntent::CompleteWithReplace => true,
22150                CompletionIntent::Complete | CompletionIntent::Compose => {
22151                    let insert_mode =
22152                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22153                            .completions
22154                            .lsp_insert_mode;
22155                    match insert_mode {
22156                        LspInsertMode::Insert => false,
22157                        LspInsertMode::Replace => true,
22158                        LspInsertMode::ReplaceSubsequence => {
22159                            let mut text_to_replace = buffer.chars_for_range(
22160                                buffer.anchor_before(replace_range.start)
22161                                    ..buffer.anchor_after(replace_range.end),
22162                            );
22163                            let mut current_needle = text_to_replace.next();
22164                            for haystack_ch in completion.label.text.chars() {
22165                                if let Some(needle_ch) = current_needle
22166                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22167                                {
22168                                    current_needle = text_to_replace.next();
22169                                }
22170                            }
22171                            current_needle.is_none()
22172                        }
22173                        LspInsertMode::ReplaceSuffix => {
22174                            if replace_range
22175                                .end
22176                                .cmp(cursor_position, &buffer_snapshot)
22177                                .is_gt()
22178                            {
22179                                let range_after_cursor = *cursor_position..replace_range.end;
22180                                let text_after_cursor = buffer
22181                                    .text_for_range(
22182                                        buffer.anchor_before(range_after_cursor.start)
22183                                            ..buffer.anchor_after(range_after_cursor.end),
22184                                    )
22185                                    .collect::<String>()
22186                                    .to_ascii_lowercase();
22187                                completion
22188                                    .label
22189                                    .text
22190                                    .to_ascii_lowercase()
22191                                    .ends_with(&text_after_cursor)
22192                            } else {
22193                                true
22194                            }
22195                        }
22196                    }
22197                }
22198            };
22199
22200            if should_replace {
22201                replace_range.clone()
22202            } else {
22203                insert_range.clone()
22204            }
22205        } else {
22206            replace_range.clone()
22207        }
22208    };
22209
22210    if range_to_replace
22211        .end
22212        .cmp(cursor_position, &buffer_snapshot)
22213        .is_lt()
22214    {
22215        range_to_replace.end = *cursor_position;
22216    }
22217
22218    CompletionEdit {
22219        new_text,
22220        replace_range: range_to_replace.to_offset(buffer),
22221        snippet,
22222    }
22223}
22224
22225struct CompletionEdit {
22226    new_text: String,
22227    replace_range: Range<usize>,
22228    snippet: Option<Snippet>,
22229}
22230
22231fn insert_extra_newline_brackets(
22232    buffer: &MultiBufferSnapshot,
22233    range: Range<usize>,
22234    language: &language::LanguageScope,
22235) -> bool {
22236    let leading_whitespace_len = buffer
22237        .reversed_chars_at(range.start)
22238        .take_while(|c| c.is_whitespace() && *c != '\n')
22239        .map(|c| c.len_utf8())
22240        .sum::<usize>();
22241    let trailing_whitespace_len = buffer
22242        .chars_at(range.end)
22243        .take_while(|c| c.is_whitespace() && *c != '\n')
22244        .map(|c| c.len_utf8())
22245        .sum::<usize>();
22246    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22247
22248    language.brackets().any(|(pair, enabled)| {
22249        let pair_start = pair.start.trim_end();
22250        let pair_end = pair.end.trim_start();
22251
22252        enabled
22253            && pair.newline
22254            && buffer.contains_str_at(range.end, pair_end)
22255            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22256    })
22257}
22258
22259fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22260    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22261        [(buffer, range, _)] => (*buffer, range.clone()),
22262        _ => return false,
22263    };
22264    let pair = {
22265        let mut result: Option<BracketMatch> = None;
22266
22267        for pair in buffer
22268            .all_bracket_ranges(range.clone())
22269            .filter(move |pair| {
22270                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22271            })
22272        {
22273            let len = pair.close_range.end - pair.open_range.start;
22274
22275            if let Some(existing) = &result {
22276                let existing_len = existing.close_range.end - existing.open_range.start;
22277                if len > existing_len {
22278                    continue;
22279                }
22280            }
22281
22282            result = Some(pair);
22283        }
22284
22285        result
22286    };
22287    let Some(pair) = pair else {
22288        return false;
22289    };
22290    pair.newline_only
22291        && buffer
22292            .chars_for_range(pair.open_range.end..range.start)
22293            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22294            .all(|c| c.is_whitespace() && c != '\n')
22295}
22296
22297fn update_uncommitted_diff_for_buffer(
22298    editor: Entity<Editor>,
22299    project: &Entity<Project>,
22300    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22301    buffer: Entity<MultiBuffer>,
22302    cx: &mut App,
22303) -> Task<()> {
22304    let mut tasks = Vec::new();
22305    project.update(cx, |project, cx| {
22306        for buffer in buffers {
22307            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22308                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22309            }
22310        }
22311    });
22312    cx.spawn(async move |cx| {
22313        let diffs = future::join_all(tasks).await;
22314        if editor
22315            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22316            .unwrap_or(false)
22317        {
22318            return;
22319        }
22320
22321        buffer
22322            .update(cx, |buffer, cx| {
22323                for diff in diffs.into_iter().flatten() {
22324                    buffer.add_diff(diff, cx);
22325                }
22326            })
22327            .ok();
22328    })
22329}
22330
22331fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22332    let tab_size = tab_size.get() as usize;
22333    let mut width = offset;
22334
22335    for ch in text.chars() {
22336        width += if ch == '\t' {
22337            tab_size - (width % tab_size)
22338        } else {
22339            1
22340        };
22341    }
22342
22343    width - offset
22344}
22345
22346#[cfg(test)]
22347mod tests {
22348    use super::*;
22349
22350    #[test]
22351    fn test_string_size_with_expanded_tabs() {
22352        let nz = |val| NonZeroU32::new(val).unwrap();
22353        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22354        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22355        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22356        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22357        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22358        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22359        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22360        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22361    }
22362}
22363
22364/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22365struct WordBreakingTokenizer<'a> {
22366    input: &'a str,
22367}
22368
22369impl<'a> WordBreakingTokenizer<'a> {
22370    fn new(input: &'a str) -> Self {
22371        Self { input }
22372    }
22373}
22374
22375fn is_char_ideographic(ch: char) -> bool {
22376    use unicode_script::Script::*;
22377    use unicode_script::UnicodeScript;
22378    matches!(ch.script(), Han | Tangut | Yi)
22379}
22380
22381fn is_grapheme_ideographic(text: &str) -> bool {
22382    text.chars().any(is_char_ideographic)
22383}
22384
22385fn is_grapheme_whitespace(text: &str) -> bool {
22386    text.chars().any(|x| x.is_whitespace())
22387}
22388
22389fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22390    text.chars()
22391        .next()
22392        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22393}
22394
22395#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22396enum WordBreakToken<'a> {
22397    Word { token: &'a str, grapheme_len: usize },
22398    InlineWhitespace { token: &'a str, grapheme_len: usize },
22399    Newline,
22400}
22401
22402impl<'a> Iterator for WordBreakingTokenizer<'a> {
22403    /// Yields a span, the count of graphemes in the token, and whether it was
22404    /// whitespace. Note that it also breaks at word boundaries.
22405    type Item = WordBreakToken<'a>;
22406
22407    fn next(&mut self) -> Option<Self::Item> {
22408        use unicode_segmentation::UnicodeSegmentation;
22409        if self.input.is_empty() {
22410            return None;
22411        }
22412
22413        let mut iter = self.input.graphemes(true).peekable();
22414        let mut offset = 0;
22415        let mut grapheme_len = 0;
22416        if let Some(first_grapheme) = iter.next() {
22417            let is_newline = first_grapheme == "\n";
22418            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22419            offset += first_grapheme.len();
22420            grapheme_len += 1;
22421            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22422                if let Some(grapheme) = iter.peek().copied()
22423                    && should_stay_with_preceding_ideograph(grapheme)
22424                {
22425                    offset += grapheme.len();
22426                    grapheme_len += 1;
22427                }
22428            } else {
22429                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22430                let mut next_word_bound = words.peek().copied();
22431                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22432                    next_word_bound = words.next();
22433                }
22434                while let Some(grapheme) = iter.peek().copied() {
22435                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22436                        break;
22437                    };
22438                    if is_grapheme_whitespace(grapheme) != is_whitespace
22439                        || (grapheme == "\n") != is_newline
22440                    {
22441                        break;
22442                    };
22443                    offset += grapheme.len();
22444                    grapheme_len += 1;
22445                    iter.next();
22446                }
22447            }
22448            let token = &self.input[..offset];
22449            self.input = &self.input[offset..];
22450            if token == "\n" {
22451                Some(WordBreakToken::Newline)
22452            } else if is_whitespace {
22453                Some(WordBreakToken::InlineWhitespace {
22454                    token,
22455                    grapheme_len,
22456                })
22457            } else {
22458                Some(WordBreakToken::Word {
22459                    token,
22460                    grapheme_len,
22461                })
22462            }
22463        } else {
22464            None
22465        }
22466    }
22467}
22468
22469#[test]
22470fn test_word_breaking_tokenizer() {
22471    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22472        ("", &[]),
22473        ("  ", &[whitespace("  ", 2)]),
22474        ("Ʒ", &[word("Ʒ", 1)]),
22475        ("Ǽ", &[word("Ǽ", 1)]),
22476        ("", &[word("", 1)]),
22477        ("⋑⋑", &[word("⋑⋑", 2)]),
22478        (
22479            "原理,进而",
22480            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22481        ),
22482        (
22483            "hello world",
22484            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22485        ),
22486        (
22487            "hello, world",
22488            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22489        ),
22490        (
22491            "  hello world",
22492            &[
22493                whitespace("  ", 2),
22494                word("hello", 5),
22495                whitespace(" ", 1),
22496                word("world", 5),
22497            ],
22498        ),
22499        (
22500            "这是什么 \n 钢笔",
22501            &[
22502                word("", 1),
22503                word("", 1),
22504                word("", 1),
22505                word("", 1),
22506                whitespace(" ", 1),
22507                newline(),
22508                whitespace(" ", 1),
22509                word("", 1),
22510                word("", 1),
22511            ],
22512        ),
22513        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22514    ];
22515
22516    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22517        WordBreakToken::Word {
22518            token,
22519            grapheme_len,
22520        }
22521    }
22522
22523    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22524        WordBreakToken::InlineWhitespace {
22525            token,
22526            grapheme_len,
22527        }
22528    }
22529
22530    fn newline() -> WordBreakToken<'static> {
22531        WordBreakToken::Newline
22532    }
22533
22534    for (input, result) in tests {
22535        assert_eq!(
22536            WordBreakingTokenizer::new(input)
22537                .collect::<Vec<_>>()
22538                .as_slice(),
22539            *result,
22540        );
22541    }
22542}
22543
22544fn wrap_with_prefix(
22545    first_line_prefix: String,
22546    subsequent_lines_prefix: String,
22547    unwrapped_text: String,
22548    wrap_column: usize,
22549    tab_size: NonZeroU32,
22550    preserve_existing_whitespace: bool,
22551) -> String {
22552    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22553    let subsequent_lines_prefix_len =
22554        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22555    let mut wrapped_text = String::new();
22556    let mut current_line = first_line_prefix;
22557    let mut is_first_line = true;
22558
22559    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22560    let mut current_line_len = first_line_prefix_len;
22561    let mut in_whitespace = false;
22562    for token in tokenizer {
22563        let have_preceding_whitespace = in_whitespace;
22564        match token {
22565            WordBreakToken::Word {
22566                token,
22567                grapheme_len,
22568            } => {
22569                in_whitespace = false;
22570                let current_prefix_len = if is_first_line {
22571                    first_line_prefix_len
22572                } else {
22573                    subsequent_lines_prefix_len
22574                };
22575                if current_line_len + grapheme_len > wrap_column
22576                    && current_line_len != current_prefix_len
22577                {
22578                    wrapped_text.push_str(current_line.trim_end());
22579                    wrapped_text.push('\n');
22580                    is_first_line = false;
22581                    current_line = subsequent_lines_prefix.clone();
22582                    current_line_len = subsequent_lines_prefix_len;
22583                }
22584                current_line.push_str(token);
22585                current_line_len += grapheme_len;
22586            }
22587            WordBreakToken::InlineWhitespace {
22588                mut token,
22589                mut grapheme_len,
22590            } => {
22591                in_whitespace = true;
22592                if have_preceding_whitespace && !preserve_existing_whitespace {
22593                    continue;
22594                }
22595                if !preserve_existing_whitespace {
22596                    // Keep a single whitespace grapheme as-is
22597                    if let Some(first) =
22598                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22599                    {
22600                        token = first;
22601                    } else {
22602                        token = " ";
22603                    }
22604                    grapheme_len = 1;
22605                }
22606                let current_prefix_len = if is_first_line {
22607                    first_line_prefix_len
22608                } else {
22609                    subsequent_lines_prefix_len
22610                };
22611                if current_line_len + grapheme_len > wrap_column {
22612                    wrapped_text.push_str(current_line.trim_end());
22613                    wrapped_text.push('\n');
22614                    is_first_line = false;
22615                    current_line = subsequent_lines_prefix.clone();
22616                    current_line_len = subsequent_lines_prefix_len;
22617                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22618                    current_line.push_str(token);
22619                    current_line_len += grapheme_len;
22620                }
22621            }
22622            WordBreakToken::Newline => {
22623                in_whitespace = true;
22624                let current_prefix_len = if is_first_line {
22625                    first_line_prefix_len
22626                } else {
22627                    subsequent_lines_prefix_len
22628                };
22629                if preserve_existing_whitespace {
22630                    wrapped_text.push_str(current_line.trim_end());
22631                    wrapped_text.push('\n');
22632                    is_first_line = false;
22633                    current_line = subsequent_lines_prefix.clone();
22634                    current_line_len = subsequent_lines_prefix_len;
22635                } else if have_preceding_whitespace {
22636                    continue;
22637                } else if current_line_len + 1 > wrap_column
22638                    && current_line_len != current_prefix_len
22639                {
22640                    wrapped_text.push_str(current_line.trim_end());
22641                    wrapped_text.push('\n');
22642                    is_first_line = false;
22643                    current_line = subsequent_lines_prefix.clone();
22644                    current_line_len = subsequent_lines_prefix_len;
22645                } else if current_line_len != current_prefix_len {
22646                    current_line.push(' ');
22647                    current_line_len += 1;
22648                }
22649            }
22650        }
22651    }
22652
22653    if !current_line.is_empty() {
22654        wrapped_text.push_str(&current_line);
22655    }
22656    wrapped_text
22657}
22658
22659#[test]
22660fn test_wrap_with_prefix() {
22661    assert_eq!(
22662        wrap_with_prefix(
22663            "# ".to_string(),
22664            "# ".to_string(),
22665            "abcdefg".to_string(),
22666            4,
22667            NonZeroU32::new(4).unwrap(),
22668            false,
22669        ),
22670        "# abcdefg"
22671    );
22672    assert_eq!(
22673        wrap_with_prefix(
22674            "".to_string(),
22675            "".to_string(),
22676            "\thello world".to_string(),
22677            8,
22678            NonZeroU32::new(4).unwrap(),
22679            false,
22680        ),
22681        "hello\nworld"
22682    );
22683    assert_eq!(
22684        wrap_with_prefix(
22685            "// ".to_string(),
22686            "// ".to_string(),
22687            "xx \nyy zz aa bb cc".to_string(),
22688            12,
22689            NonZeroU32::new(4).unwrap(),
22690            false,
22691        ),
22692        "// xx yy zz\n// aa bb cc"
22693    );
22694    assert_eq!(
22695        wrap_with_prefix(
22696            String::new(),
22697            String::new(),
22698            "这是什么 \n 钢笔".to_string(),
22699            3,
22700            NonZeroU32::new(4).unwrap(),
22701            false,
22702        ),
22703        "这是什\n么 钢\n"
22704    );
22705    assert_eq!(
22706        wrap_with_prefix(
22707            String::new(),
22708            String::new(),
22709            format!("foo{}bar", '\u{2009}'), // thin space
22710            80,
22711            NonZeroU32::new(4).unwrap(),
22712            false,
22713        ),
22714        format!("foo{}bar", '\u{2009}')
22715    );
22716}
22717
22718pub trait CollaborationHub {
22719    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22720    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22721    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22722}
22723
22724impl CollaborationHub for Entity<Project> {
22725    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22726        self.read(cx).collaborators()
22727    }
22728
22729    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22730        self.read(cx).user_store().read(cx).participant_indices()
22731    }
22732
22733    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22734        let this = self.read(cx);
22735        let user_ids = this.collaborators().values().map(|c| c.user_id);
22736        this.user_store().read(cx).participant_names(user_ids, cx)
22737    }
22738}
22739
22740pub trait SemanticsProvider {
22741    fn hover(
22742        &self,
22743        buffer: &Entity<Buffer>,
22744        position: text::Anchor,
22745        cx: &mut App,
22746    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22747
22748    fn inline_values(
22749        &self,
22750        buffer_handle: Entity<Buffer>,
22751        range: Range<text::Anchor>,
22752        cx: &mut App,
22753    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22754
22755    fn inlay_hints(
22756        &self,
22757        buffer_handle: Entity<Buffer>,
22758        range: Range<text::Anchor>,
22759        cx: &mut App,
22760    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22761
22762    fn resolve_inlay_hint(
22763        &self,
22764        hint: InlayHint,
22765        buffer_handle: Entity<Buffer>,
22766        server_id: LanguageServerId,
22767        cx: &mut App,
22768    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22769
22770    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22771
22772    fn document_highlights(
22773        &self,
22774        buffer: &Entity<Buffer>,
22775        position: text::Anchor,
22776        cx: &mut App,
22777    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22778
22779    fn definitions(
22780        &self,
22781        buffer: &Entity<Buffer>,
22782        position: text::Anchor,
22783        kind: GotoDefinitionKind,
22784        cx: &mut App,
22785    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22786
22787    fn range_for_rename(
22788        &self,
22789        buffer: &Entity<Buffer>,
22790        position: text::Anchor,
22791        cx: &mut App,
22792    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22793
22794    fn perform_rename(
22795        &self,
22796        buffer: &Entity<Buffer>,
22797        position: text::Anchor,
22798        new_name: String,
22799        cx: &mut App,
22800    ) -> Option<Task<Result<ProjectTransaction>>>;
22801}
22802
22803pub trait CompletionProvider {
22804    fn completions(
22805        &self,
22806        excerpt_id: ExcerptId,
22807        buffer: &Entity<Buffer>,
22808        buffer_position: text::Anchor,
22809        trigger: CompletionContext,
22810        window: &mut Window,
22811        cx: &mut Context<Editor>,
22812    ) -> Task<Result<Vec<CompletionResponse>>>;
22813
22814    fn resolve_completions(
22815        &self,
22816        _buffer: Entity<Buffer>,
22817        _completion_indices: Vec<usize>,
22818        _completions: Rc<RefCell<Box<[Completion]>>>,
22819        _cx: &mut Context<Editor>,
22820    ) -> Task<Result<bool>> {
22821        Task::ready(Ok(false))
22822    }
22823
22824    fn apply_additional_edits_for_completion(
22825        &self,
22826        _buffer: Entity<Buffer>,
22827        _completions: Rc<RefCell<Box<[Completion]>>>,
22828        _completion_index: usize,
22829        _push_to_history: bool,
22830        _cx: &mut Context<Editor>,
22831    ) -> Task<Result<Option<language::Transaction>>> {
22832        Task::ready(Ok(None))
22833    }
22834
22835    fn is_completion_trigger(
22836        &self,
22837        buffer: &Entity<Buffer>,
22838        position: language::Anchor,
22839        text: &str,
22840        trigger_in_words: bool,
22841        menu_is_open: bool,
22842        cx: &mut Context<Editor>,
22843    ) -> bool;
22844
22845    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22846
22847    fn sort_completions(&self) -> bool {
22848        true
22849    }
22850
22851    fn filter_completions(&self) -> bool {
22852        true
22853    }
22854}
22855
22856pub trait CodeActionProvider {
22857    fn id(&self) -> Arc<str>;
22858
22859    fn code_actions(
22860        &self,
22861        buffer: &Entity<Buffer>,
22862        range: Range<text::Anchor>,
22863        window: &mut Window,
22864        cx: &mut App,
22865    ) -> Task<Result<Vec<CodeAction>>>;
22866
22867    fn apply_code_action(
22868        &self,
22869        buffer_handle: Entity<Buffer>,
22870        action: CodeAction,
22871        excerpt_id: ExcerptId,
22872        push_to_history: bool,
22873        window: &mut Window,
22874        cx: &mut App,
22875    ) -> Task<Result<ProjectTransaction>>;
22876}
22877
22878impl CodeActionProvider for Entity<Project> {
22879    fn id(&self) -> Arc<str> {
22880        "project".into()
22881    }
22882
22883    fn code_actions(
22884        &self,
22885        buffer: &Entity<Buffer>,
22886        range: Range<text::Anchor>,
22887        _window: &mut Window,
22888        cx: &mut App,
22889    ) -> Task<Result<Vec<CodeAction>>> {
22890        self.update(cx, |project, cx| {
22891            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22892            let code_actions = project.code_actions(buffer, range, None, cx);
22893            cx.background_spawn(async move {
22894                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22895                Ok(code_lens_actions
22896                    .context("code lens fetch")?
22897                    .into_iter()
22898                    .flatten()
22899                    .chain(
22900                        code_actions
22901                            .context("code action fetch")?
22902                            .into_iter()
22903                            .flatten(),
22904                    )
22905                    .collect())
22906            })
22907        })
22908    }
22909
22910    fn apply_code_action(
22911        &self,
22912        buffer_handle: Entity<Buffer>,
22913        action: CodeAction,
22914        _excerpt_id: ExcerptId,
22915        push_to_history: bool,
22916        _window: &mut Window,
22917        cx: &mut App,
22918    ) -> Task<Result<ProjectTransaction>> {
22919        self.update(cx, |project, cx| {
22920            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22921        })
22922    }
22923}
22924
22925fn snippet_completions(
22926    project: &Project,
22927    buffer: &Entity<Buffer>,
22928    buffer_position: text::Anchor,
22929    cx: &mut App,
22930) -> Task<Result<CompletionResponse>> {
22931    let languages = buffer.read(cx).languages_at(buffer_position);
22932    let snippet_store = project.snippets().read(cx);
22933
22934    let scopes: Vec<_> = languages
22935        .iter()
22936        .filter_map(|language| {
22937            let language_name = language.lsp_id();
22938            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22939
22940            if snippets.is_empty() {
22941                None
22942            } else {
22943                Some((language.default_scope(), snippets))
22944            }
22945        })
22946        .collect();
22947
22948    if scopes.is_empty() {
22949        return Task::ready(Ok(CompletionResponse {
22950            completions: vec![],
22951            display_options: CompletionDisplayOptions::default(),
22952            is_incomplete: false,
22953        }));
22954    }
22955
22956    let snapshot = buffer.read(cx).text_snapshot();
22957    let executor = cx.background_executor().clone();
22958
22959    cx.background_spawn(async move {
22960        let mut is_incomplete = false;
22961        let mut completions: Vec<Completion> = Vec::new();
22962        for (scope, snippets) in scopes.into_iter() {
22963            let classifier =
22964                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22965
22966            const MAX_WORD_PREFIX_LEN: usize = 128;
22967            let last_word: String = snapshot
22968                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22969                .take(MAX_WORD_PREFIX_LEN)
22970                .take_while(|c| classifier.is_word(*c))
22971                .collect::<String>()
22972                .chars()
22973                .rev()
22974                .collect();
22975
22976            if last_word.is_empty() {
22977                return Ok(CompletionResponse {
22978                    completions: vec![],
22979                    display_options: CompletionDisplayOptions::default(),
22980                    is_incomplete: true,
22981                });
22982            }
22983
22984            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22985            let to_lsp = |point: &text::Anchor| {
22986                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22987                point_to_lsp(end)
22988            };
22989            let lsp_end = to_lsp(&buffer_position);
22990
22991            let candidates = snippets
22992                .iter()
22993                .enumerate()
22994                .flat_map(|(ix, snippet)| {
22995                    snippet
22996                        .prefix
22997                        .iter()
22998                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22999                })
23000                .collect::<Vec<StringMatchCandidate>>();
23001
23002            const MAX_RESULTS: usize = 100;
23003            let mut matches = fuzzy::match_strings(
23004                &candidates,
23005                &last_word,
23006                last_word.chars().any(|c| c.is_uppercase()),
23007                true,
23008                MAX_RESULTS,
23009                &Default::default(),
23010                executor.clone(),
23011            )
23012            .await;
23013
23014            if matches.len() >= MAX_RESULTS {
23015                is_incomplete = true;
23016            }
23017
23018            // Remove all candidates where the query's start does not match the start of any word in the candidate
23019            if let Some(query_start) = last_word.chars().next() {
23020                matches.retain(|string_match| {
23021                    split_words(&string_match.string).any(|word| {
23022                        // Check that the first codepoint of the word as lowercase matches the first
23023                        // codepoint of the query as lowercase
23024                        word.chars()
23025                            .flat_map(|codepoint| codepoint.to_lowercase())
23026                            .zip(query_start.to_lowercase())
23027                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23028                    })
23029                });
23030            }
23031
23032            let matched_strings = matches
23033                .into_iter()
23034                .map(|m| m.string)
23035                .collect::<HashSet<_>>();
23036
23037            completions.extend(snippets.iter().filter_map(|snippet| {
23038                let matching_prefix = snippet
23039                    .prefix
23040                    .iter()
23041                    .find(|prefix| matched_strings.contains(*prefix))?;
23042                let start = as_offset - last_word.len();
23043                let start = snapshot.anchor_before(start);
23044                let range = start..buffer_position;
23045                let lsp_start = to_lsp(&start);
23046                let lsp_range = lsp::Range {
23047                    start: lsp_start,
23048                    end: lsp_end,
23049                };
23050                Some(Completion {
23051                    replace_range: range,
23052                    new_text: snippet.body.clone(),
23053                    source: CompletionSource::Lsp {
23054                        insert_range: None,
23055                        server_id: LanguageServerId(usize::MAX),
23056                        resolved: true,
23057                        lsp_completion: Box::new(lsp::CompletionItem {
23058                            label: snippet.prefix.first().unwrap().clone(),
23059                            kind: Some(CompletionItemKind::SNIPPET),
23060                            label_details: snippet.description.as_ref().map(|description| {
23061                                lsp::CompletionItemLabelDetails {
23062                                    detail: Some(description.clone()),
23063                                    description: None,
23064                                }
23065                            }),
23066                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23067                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23068                                lsp::InsertReplaceEdit {
23069                                    new_text: snippet.body.clone(),
23070                                    insert: lsp_range,
23071                                    replace: lsp_range,
23072                                },
23073                            )),
23074                            filter_text: Some(snippet.body.clone()),
23075                            sort_text: Some(char::MAX.to_string()),
23076                            ..lsp::CompletionItem::default()
23077                        }),
23078                        lsp_defaults: None,
23079                    },
23080                    label: CodeLabel {
23081                        text: matching_prefix.clone(),
23082                        runs: Vec::new(),
23083                        filter_range: 0..matching_prefix.len(),
23084                    },
23085                    icon_path: None,
23086                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23087                        single_line: snippet.name.clone().into(),
23088                        plain_text: snippet
23089                            .description
23090                            .clone()
23091                            .map(|description| description.into()),
23092                    }),
23093                    insert_text_mode: None,
23094                    confirm: None,
23095                })
23096            }))
23097        }
23098
23099        Ok(CompletionResponse {
23100            completions,
23101            display_options: CompletionDisplayOptions::default(),
23102            is_incomplete,
23103        })
23104    })
23105}
23106
23107impl CompletionProvider for Entity<Project> {
23108    fn completions(
23109        &self,
23110        _excerpt_id: ExcerptId,
23111        buffer: &Entity<Buffer>,
23112        buffer_position: text::Anchor,
23113        options: CompletionContext,
23114        _window: &mut Window,
23115        cx: &mut Context<Editor>,
23116    ) -> Task<Result<Vec<CompletionResponse>>> {
23117        self.update(cx, |project, cx| {
23118            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23119            let project_completions = project.completions(buffer, buffer_position, options, cx);
23120            cx.background_spawn(async move {
23121                let mut responses = project_completions.await?;
23122                let snippets = snippets.await?;
23123                if !snippets.completions.is_empty() {
23124                    responses.push(snippets);
23125                }
23126                Ok(responses)
23127            })
23128        })
23129    }
23130
23131    fn resolve_completions(
23132        &self,
23133        buffer: Entity<Buffer>,
23134        completion_indices: Vec<usize>,
23135        completions: Rc<RefCell<Box<[Completion]>>>,
23136        cx: &mut Context<Editor>,
23137    ) -> Task<Result<bool>> {
23138        self.update(cx, |project, cx| {
23139            project.lsp_store().update(cx, |lsp_store, cx| {
23140                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23141            })
23142        })
23143    }
23144
23145    fn apply_additional_edits_for_completion(
23146        &self,
23147        buffer: Entity<Buffer>,
23148        completions: Rc<RefCell<Box<[Completion]>>>,
23149        completion_index: usize,
23150        push_to_history: bool,
23151        cx: &mut Context<Editor>,
23152    ) -> Task<Result<Option<language::Transaction>>> {
23153        self.update(cx, |project, cx| {
23154            project.lsp_store().update(cx, |lsp_store, cx| {
23155                lsp_store.apply_additional_edits_for_completion(
23156                    buffer,
23157                    completions,
23158                    completion_index,
23159                    push_to_history,
23160                    cx,
23161                )
23162            })
23163        })
23164    }
23165
23166    fn is_completion_trigger(
23167        &self,
23168        buffer: &Entity<Buffer>,
23169        position: language::Anchor,
23170        text: &str,
23171        trigger_in_words: bool,
23172        menu_is_open: bool,
23173        cx: &mut Context<Editor>,
23174    ) -> bool {
23175        let mut chars = text.chars();
23176        let char = if let Some(char) = chars.next() {
23177            char
23178        } else {
23179            return false;
23180        };
23181        if chars.next().is_some() {
23182            return false;
23183        }
23184
23185        let buffer = buffer.read(cx);
23186        let snapshot = buffer.snapshot();
23187        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23188            return false;
23189        }
23190        let classifier = snapshot
23191            .char_classifier_at(position)
23192            .scope_context(Some(CharScopeContext::Completion));
23193        if trigger_in_words && classifier.is_word(char) {
23194            return true;
23195        }
23196
23197        buffer.completion_triggers().contains(text)
23198    }
23199}
23200
23201impl SemanticsProvider for Entity<Project> {
23202    fn hover(
23203        &self,
23204        buffer: &Entity<Buffer>,
23205        position: text::Anchor,
23206        cx: &mut App,
23207    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23208        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23209    }
23210
23211    fn document_highlights(
23212        &self,
23213        buffer: &Entity<Buffer>,
23214        position: text::Anchor,
23215        cx: &mut App,
23216    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23217        Some(self.update(cx, |project, cx| {
23218            project.document_highlights(buffer, position, cx)
23219        }))
23220    }
23221
23222    fn definitions(
23223        &self,
23224        buffer: &Entity<Buffer>,
23225        position: text::Anchor,
23226        kind: GotoDefinitionKind,
23227        cx: &mut App,
23228    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23229        Some(self.update(cx, |project, cx| match kind {
23230            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23231            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23232            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23233            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23234        }))
23235    }
23236
23237    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23238        self.update(cx, |project, cx| {
23239            if project
23240                .active_debug_session(cx)
23241                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23242            {
23243                return true;
23244            }
23245
23246            buffer.update(cx, |buffer, cx| {
23247                project.any_language_server_supports_inlay_hints(buffer, cx)
23248            })
23249        })
23250    }
23251
23252    fn inline_values(
23253        &self,
23254        buffer_handle: Entity<Buffer>,
23255        range: Range<text::Anchor>,
23256        cx: &mut App,
23257    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23258        self.update(cx, |project, cx| {
23259            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23260
23261            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23262        })
23263    }
23264
23265    fn inlay_hints(
23266        &self,
23267        buffer_handle: Entity<Buffer>,
23268        range: Range<text::Anchor>,
23269        cx: &mut App,
23270    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23271        Some(self.update(cx, |project, cx| {
23272            project.inlay_hints(buffer_handle, range, cx)
23273        }))
23274    }
23275
23276    fn resolve_inlay_hint(
23277        &self,
23278        hint: InlayHint,
23279        buffer_handle: Entity<Buffer>,
23280        server_id: LanguageServerId,
23281        cx: &mut App,
23282    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23283        Some(self.update(cx, |project, cx| {
23284            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23285        }))
23286    }
23287
23288    fn range_for_rename(
23289        &self,
23290        buffer: &Entity<Buffer>,
23291        position: text::Anchor,
23292        cx: &mut App,
23293    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23294        Some(self.update(cx, |project, cx| {
23295            let buffer = buffer.clone();
23296            let task = project.prepare_rename(buffer.clone(), position, cx);
23297            cx.spawn(async move |_, cx| {
23298                Ok(match task.await? {
23299                    PrepareRenameResponse::Success(range) => Some(range),
23300                    PrepareRenameResponse::InvalidPosition => None,
23301                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23302                        // Fallback on using TreeSitter info to determine identifier range
23303                        buffer.read_with(cx, |buffer, _| {
23304                            let snapshot = buffer.snapshot();
23305                            let (range, kind) = snapshot.surrounding_word(position, None);
23306                            if kind != Some(CharKind::Word) {
23307                                return None;
23308                            }
23309                            Some(
23310                                snapshot.anchor_before(range.start)
23311                                    ..snapshot.anchor_after(range.end),
23312                            )
23313                        })?
23314                    }
23315                })
23316            })
23317        }))
23318    }
23319
23320    fn perform_rename(
23321        &self,
23322        buffer: &Entity<Buffer>,
23323        position: text::Anchor,
23324        new_name: String,
23325        cx: &mut App,
23326    ) -> Option<Task<Result<ProjectTransaction>>> {
23327        Some(self.update(cx, |project, cx| {
23328            project.perform_rename(buffer.clone(), position, new_name, cx)
23329        }))
23330    }
23331}
23332
23333fn inlay_hint_settings(
23334    location: Anchor,
23335    snapshot: &MultiBufferSnapshot,
23336    cx: &mut Context<Editor>,
23337) -> InlayHintSettings {
23338    let file = snapshot.file_at(location);
23339    let language = snapshot.language_at(location).map(|l| l.name());
23340    language_settings(language, file, cx).inlay_hints
23341}
23342
23343fn consume_contiguous_rows(
23344    contiguous_row_selections: &mut Vec<Selection<Point>>,
23345    selection: &Selection<Point>,
23346    display_map: &DisplaySnapshot,
23347    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23348) -> (MultiBufferRow, MultiBufferRow) {
23349    contiguous_row_selections.push(selection.clone());
23350    let start_row = starting_row(selection, display_map);
23351    let mut end_row = ending_row(selection, display_map);
23352
23353    while let Some(next_selection) = selections.peek() {
23354        if next_selection.start.row <= end_row.0 {
23355            end_row = ending_row(next_selection, display_map);
23356            contiguous_row_selections.push(selections.next().unwrap().clone());
23357        } else {
23358            break;
23359        }
23360    }
23361    (start_row, end_row)
23362}
23363
23364fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23365    if selection.start.column > 0 {
23366        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23367    } else {
23368        MultiBufferRow(selection.start.row)
23369    }
23370}
23371
23372fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23373    if next_selection.end.column > 0 || next_selection.is_empty() {
23374        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23375    } else {
23376        MultiBufferRow(next_selection.end.row)
23377    }
23378}
23379
23380impl EditorSnapshot {
23381    pub fn remote_selections_in_range<'a>(
23382        &'a self,
23383        range: &'a Range<Anchor>,
23384        collaboration_hub: &dyn CollaborationHub,
23385        cx: &'a App,
23386    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23387        let participant_names = collaboration_hub.user_names(cx);
23388        let participant_indices = collaboration_hub.user_participant_indices(cx);
23389        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23390        let collaborators_by_replica_id = collaborators_by_peer_id
23391            .values()
23392            .map(|collaborator| (collaborator.replica_id, collaborator))
23393            .collect::<HashMap<_, _>>();
23394        self.buffer_snapshot()
23395            .selections_in_range(range, false)
23396            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23397                if replica_id == AGENT_REPLICA_ID {
23398                    Some(RemoteSelection {
23399                        replica_id,
23400                        selection,
23401                        cursor_shape,
23402                        line_mode,
23403                        collaborator_id: CollaboratorId::Agent,
23404                        user_name: Some("Agent".into()),
23405                        color: cx.theme().players().agent(),
23406                    })
23407                } else {
23408                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23409                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23410                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23411                    Some(RemoteSelection {
23412                        replica_id,
23413                        selection,
23414                        cursor_shape,
23415                        line_mode,
23416                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23417                        user_name,
23418                        color: if let Some(index) = participant_index {
23419                            cx.theme().players().color_for_participant(index.0)
23420                        } else {
23421                            cx.theme().players().absent()
23422                        },
23423                    })
23424                }
23425            })
23426    }
23427
23428    pub fn hunks_for_ranges(
23429        &self,
23430        ranges: impl IntoIterator<Item = Range<Point>>,
23431    ) -> Vec<MultiBufferDiffHunk> {
23432        let mut hunks = Vec::new();
23433        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23434            HashMap::default();
23435        for query_range in ranges {
23436            let query_rows =
23437                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23438            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23439                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23440            ) {
23441                // Include deleted hunks that are adjacent to the query range, because
23442                // otherwise they would be missed.
23443                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23444                if hunk.status().is_deleted() {
23445                    intersects_range |= hunk.row_range.start == query_rows.end;
23446                    intersects_range |= hunk.row_range.end == query_rows.start;
23447                }
23448                if intersects_range {
23449                    if !processed_buffer_rows
23450                        .entry(hunk.buffer_id)
23451                        .or_default()
23452                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23453                    {
23454                        continue;
23455                    }
23456                    hunks.push(hunk);
23457                }
23458            }
23459        }
23460
23461        hunks
23462    }
23463
23464    fn display_diff_hunks_for_rows<'a>(
23465        &'a self,
23466        display_rows: Range<DisplayRow>,
23467        folded_buffers: &'a HashSet<BufferId>,
23468    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23469        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23470        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23471
23472        self.buffer_snapshot()
23473            .diff_hunks_in_range(buffer_start..buffer_end)
23474            .filter_map(|hunk| {
23475                if folded_buffers.contains(&hunk.buffer_id) {
23476                    return None;
23477                }
23478
23479                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23480                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23481
23482                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23483                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23484
23485                let display_hunk = if hunk_display_start.column() != 0 {
23486                    DisplayDiffHunk::Folded {
23487                        display_row: hunk_display_start.row(),
23488                    }
23489                } else {
23490                    let mut end_row = hunk_display_end.row();
23491                    if hunk_display_end.column() > 0 {
23492                        end_row.0 += 1;
23493                    }
23494                    let is_created_file = hunk.is_created_file();
23495                    DisplayDiffHunk::Unfolded {
23496                        status: hunk.status(),
23497                        diff_base_byte_range: hunk.diff_base_byte_range,
23498                        display_row_range: hunk_display_start.row()..end_row,
23499                        multi_buffer_range: Anchor::range_in_buffer(
23500                            hunk.excerpt_id,
23501                            hunk.buffer_id,
23502                            hunk.buffer_range,
23503                        ),
23504                        is_created_file,
23505                    }
23506                };
23507
23508                Some(display_hunk)
23509            })
23510    }
23511
23512    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23513        self.display_snapshot
23514            .buffer_snapshot()
23515            .language_at(position)
23516    }
23517
23518    pub fn is_focused(&self) -> bool {
23519        self.is_focused
23520    }
23521
23522    pub fn placeholder_text(&self) -> Option<String> {
23523        self.placeholder_display_snapshot
23524            .as_ref()
23525            .map(|display_map| display_map.text())
23526    }
23527
23528    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23529        self.scroll_anchor.scroll_position(&self.display_snapshot)
23530    }
23531
23532    fn gutter_dimensions(
23533        &self,
23534        font_id: FontId,
23535        font_size: Pixels,
23536        max_line_number_width: Pixels,
23537        cx: &App,
23538    ) -> Option<GutterDimensions> {
23539        if !self.show_gutter {
23540            return None;
23541        }
23542
23543        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23544        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23545
23546        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23547            matches!(
23548                ProjectSettings::get_global(cx).git.git_gutter,
23549                GitGutterSetting::TrackedFiles
23550            )
23551        });
23552        let gutter_settings = EditorSettings::get_global(cx).gutter;
23553        let show_line_numbers = self
23554            .show_line_numbers
23555            .unwrap_or(gutter_settings.line_numbers);
23556        let line_gutter_width = if show_line_numbers {
23557            // Avoid flicker-like gutter resizes when the line number gains another digit by
23558            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23559            let min_width_for_number_on_gutter =
23560                ch_advance * gutter_settings.min_line_number_digits as f32;
23561            max_line_number_width.max(min_width_for_number_on_gutter)
23562        } else {
23563            0.0.into()
23564        };
23565
23566        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23567        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23568
23569        let git_blame_entries_width =
23570            self.git_blame_gutter_max_author_length
23571                .map(|max_author_length| {
23572                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23573                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23574
23575                    /// The number of characters to dedicate to gaps and margins.
23576                    const SPACING_WIDTH: usize = 4;
23577
23578                    let max_char_count = max_author_length.min(renderer.max_author_length())
23579                        + ::git::SHORT_SHA_LENGTH
23580                        + MAX_RELATIVE_TIMESTAMP.len()
23581                        + SPACING_WIDTH;
23582
23583                    ch_advance * max_char_count
23584                });
23585
23586        let is_singleton = self.buffer_snapshot().is_singleton();
23587
23588        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23589        left_padding += if !is_singleton {
23590            ch_width * 4.0
23591        } else if show_runnables || show_breakpoints {
23592            ch_width * 3.0
23593        } else if show_git_gutter && show_line_numbers {
23594            ch_width * 2.0
23595        } else if show_git_gutter || show_line_numbers {
23596            ch_width
23597        } else {
23598            px(0.)
23599        };
23600
23601        let shows_folds = is_singleton && gutter_settings.folds;
23602
23603        let right_padding = if shows_folds && show_line_numbers {
23604            ch_width * 4.0
23605        } else if shows_folds || (!is_singleton && show_line_numbers) {
23606            ch_width * 3.0
23607        } else if show_line_numbers {
23608            ch_width
23609        } else {
23610            px(0.)
23611        };
23612
23613        Some(GutterDimensions {
23614            left_padding,
23615            right_padding,
23616            width: line_gutter_width + left_padding + right_padding,
23617            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23618            git_blame_entries_width,
23619        })
23620    }
23621
23622    pub fn render_crease_toggle(
23623        &self,
23624        buffer_row: MultiBufferRow,
23625        row_contains_cursor: bool,
23626        editor: Entity<Editor>,
23627        window: &mut Window,
23628        cx: &mut App,
23629    ) -> Option<AnyElement> {
23630        let folded = self.is_line_folded(buffer_row);
23631        let mut is_foldable = false;
23632
23633        if let Some(crease) = self
23634            .crease_snapshot
23635            .query_row(buffer_row, self.buffer_snapshot())
23636        {
23637            is_foldable = true;
23638            match crease {
23639                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23640                    if let Some(render_toggle) = render_toggle {
23641                        let toggle_callback =
23642                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23643                                if folded {
23644                                    editor.update(cx, |editor, cx| {
23645                                        editor.fold_at(buffer_row, window, cx)
23646                                    });
23647                                } else {
23648                                    editor.update(cx, |editor, cx| {
23649                                        editor.unfold_at(buffer_row, window, cx)
23650                                    });
23651                                }
23652                            });
23653                        return Some((render_toggle)(
23654                            buffer_row,
23655                            folded,
23656                            toggle_callback,
23657                            window,
23658                            cx,
23659                        ));
23660                    }
23661                }
23662            }
23663        }
23664
23665        is_foldable |= self.starts_indent(buffer_row);
23666
23667        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23668            Some(
23669                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23670                    .toggle_state(folded)
23671                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23672                        if folded {
23673                            this.unfold_at(buffer_row, window, cx);
23674                        } else {
23675                            this.fold_at(buffer_row, window, cx);
23676                        }
23677                    }))
23678                    .into_any_element(),
23679            )
23680        } else {
23681            None
23682        }
23683    }
23684
23685    pub fn render_crease_trailer(
23686        &self,
23687        buffer_row: MultiBufferRow,
23688        window: &mut Window,
23689        cx: &mut App,
23690    ) -> Option<AnyElement> {
23691        let folded = self.is_line_folded(buffer_row);
23692        if let Crease::Inline { render_trailer, .. } = self
23693            .crease_snapshot
23694            .query_row(buffer_row, self.buffer_snapshot())?
23695        {
23696            let render_trailer = render_trailer.as_ref()?;
23697            Some(render_trailer(buffer_row, folded, window, cx))
23698        } else {
23699            None
23700        }
23701    }
23702}
23703
23704impl Deref for EditorSnapshot {
23705    type Target = DisplaySnapshot;
23706
23707    fn deref(&self) -> &Self::Target {
23708        &self.display_snapshot
23709    }
23710}
23711
23712#[derive(Clone, Debug, PartialEq, Eq)]
23713pub enum EditorEvent {
23714    InputIgnored {
23715        text: Arc<str>,
23716    },
23717    InputHandled {
23718        utf16_range_to_replace: Option<Range<isize>>,
23719        text: Arc<str>,
23720    },
23721    ExcerptsAdded {
23722        buffer: Entity<Buffer>,
23723        predecessor: ExcerptId,
23724        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23725    },
23726    ExcerptsRemoved {
23727        ids: Vec<ExcerptId>,
23728        removed_buffer_ids: Vec<BufferId>,
23729    },
23730    BufferFoldToggled {
23731        ids: Vec<ExcerptId>,
23732        folded: bool,
23733    },
23734    ExcerptsEdited {
23735        ids: Vec<ExcerptId>,
23736    },
23737    ExcerptsExpanded {
23738        ids: Vec<ExcerptId>,
23739    },
23740    BufferEdited,
23741    Edited {
23742        transaction_id: clock::Lamport,
23743    },
23744    Reparsed(BufferId),
23745    Focused,
23746    FocusedIn,
23747    Blurred,
23748    DirtyChanged,
23749    Saved,
23750    TitleChanged,
23751    SelectionsChanged {
23752        local: bool,
23753    },
23754    ScrollPositionChanged {
23755        local: bool,
23756        autoscroll: bool,
23757    },
23758    TransactionUndone {
23759        transaction_id: clock::Lamport,
23760    },
23761    TransactionBegun {
23762        transaction_id: clock::Lamport,
23763    },
23764    CursorShapeChanged,
23765    BreadcrumbsChanged,
23766    PushedToNavHistory {
23767        anchor: Anchor,
23768        is_deactivate: bool,
23769    },
23770}
23771
23772impl EventEmitter<EditorEvent> for Editor {}
23773
23774impl Focusable for Editor {
23775    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23776        self.focus_handle.clone()
23777    }
23778}
23779
23780impl Render for Editor {
23781    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23782        let settings = ThemeSettings::get_global(cx);
23783
23784        let mut text_style = match self.mode {
23785            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23786                color: cx.theme().colors().editor_foreground,
23787                font_family: settings.ui_font.family.clone(),
23788                font_features: settings.ui_font.features.clone(),
23789                font_fallbacks: settings.ui_font.fallbacks.clone(),
23790                font_size: rems(0.875).into(),
23791                font_weight: settings.ui_font.weight,
23792                line_height: relative(settings.buffer_line_height.value()),
23793                ..Default::default()
23794            },
23795            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23796                color: cx.theme().colors().editor_foreground,
23797                font_family: settings.buffer_font.family.clone(),
23798                font_features: settings.buffer_font.features.clone(),
23799                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23800                font_size: settings.buffer_font_size(cx).into(),
23801                font_weight: settings.buffer_font.weight,
23802                line_height: relative(settings.buffer_line_height.value()),
23803                ..Default::default()
23804            },
23805        };
23806        if let Some(text_style_refinement) = &self.text_style_refinement {
23807            text_style.refine(text_style_refinement)
23808        }
23809
23810        let background = match self.mode {
23811            EditorMode::SingleLine => cx.theme().system().transparent,
23812            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23813            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23814            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23815        };
23816
23817        EditorElement::new(
23818            &cx.entity(),
23819            EditorStyle {
23820                background,
23821                border: cx.theme().colors().border,
23822                local_player: cx.theme().players().local(),
23823                text: text_style,
23824                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23825                syntax: cx.theme().syntax().clone(),
23826                status: cx.theme().status().clone(),
23827                inlay_hints_style: make_inlay_hints_style(cx),
23828                edit_prediction_styles: make_suggestion_styles(cx),
23829                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23830                show_underlines: self.diagnostics_enabled(),
23831            },
23832        )
23833    }
23834}
23835
23836impl EntityInputHandler for Editor {
23837    fn text_for_range(
23838        &mut self,
23839        range_utf16: Range<usize>,
23840        adjusted_range: &mut Option<Range<usize>>,
23841        _: &mut Window,
23842        cx: &mut Context<Self>,
23843    ) -> Option<String> {
23844        let snapshot = self.buffer.read(cx).read(cx);
23845        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23846        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23847        if (start.0..end.0) != range_utf16 {
23848            adjusted_range.replace(start.0..end.0);
23849        }
23850        Some(snapshot.text_for_range(start..end).collect())
23851    }
23852
23853    fn selected_text_range(
23854        &mut self,
23855        ignore_disabled_input: bool,
23856        _: &mut Window,
23857        cx: &mut Context<Self>,
23858    ) -> Option<UTF16Selection> {
23859        // Prevent the IME menu from appearing when holding down an alphabetic key
23860        // while input is disabled.
23861        if !ignore_disabled_input && !self.input_enabled {
23862            return None;
23863        }
23864
23865        let selection = self.selections.newest::<OffsetUtf16>(cx);
23866        let range = selection.range();
23867
23868        Some(UTF16Selection {
23869            range: range.start.0..range.end.0,
23870            reversed: selection.reversed,
23871        })
23872    }
23873
23874    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23875        let snapshot = self.buffer.read(cx).read(cx);
23876        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23877        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23878    }
23879
23880    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23881        self.clear_highlights::<InputComposition>(cx);
23882        self.ime_transaction.take();
23883    }
23884
23885    fn replace_text_in_range(
23886        &mut self,
23887        range_utf16: Option<Range<usize>>,
23888        text: &str,
23889        window: &mut Window,
23890        cx: &mut Context<Self>,
23891    ) {
23892        if !self.input_enabled {
23893            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23894            return;
23895        }
23896
23897        self.transact(window, cx, |this, window, cx| {
23898            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23899                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23900                Some(this.selection_replacement_ranges(range_utf16, cx))
23901            } else {
23902                this.marked_text_ranges(cx)
23903            };
23904
23905            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23906                let newest_selection_id = this.selections.newest_anchor().id;
23907                this.selections
23908                    .all::<OffsetUtf16>(cx)
23909                    .iter()
23910                    .zip(ranges_to_replace.iter())
23911                    .find_map(|(selection, range)| {
23912                        if selection.id == newest_selection_id {
23913                            Some(
23914                                (range.start.0 as isize - selection.head().0 as isize)
23915                                    ..(range.end.0 as isize - selection.head().0 as isize),
23916                            )
23917                        } else {
23918                            None
23919                        }
23920                    })
23921            });
23922
23923            cx.emit(EditorEvent::InputHandled {
23924                utf16_range_to_replace: range_to_replace,
23925                text: text.into(),
23926            });
23927
23928            if let Some(new_selected_ranges) = new_selected_ranges {
23929                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23930                    selections.select_ranges(new_selected_ranges)
23931                });
23932                this.backspace(&Default::default(), window, cx);
23933            }
23934
23935            this.handle_input(text, window, cx);
23936        });
23937
23938        if let Some(transaction) = self.ime_transaction {
23939            self.buffer.update(cx, |buffer, cx| {
23940                buffer.group_until_transaction(transaction, cx);
23941            });
23942        }
23943
23944        self.unmark_text(window, cx);
23945    }
23946
23947    fn replace_and_mark_text_in_range(
23948        &mut self,
23949        range_utf16: Option<Range<usize>>,
23950        text: &str,
23951        new_selected_range_utf16: Option<Range<usize>>,
23952        window: &mut Window,
23953        cx: &mut Context<Self>,
23954    ) {
23955        if !self.input_enabled {
23956            return;
23957        }
23958
23959        let transaction = self.transact(window, cx, |this, window, cx| {
23960            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23961                let snapshot = this.buffer.read(cx).read(cx);
23962                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23963                    for marked_range in &mut marked_ranges {
23964                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23965                        marked_range.start.0 += relative_range_utf16.start;
23966                        marked_range.start =
23967                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23968                        marked_range.end =
23969                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23970                    }
23971                }
23972                Some(marked_ranges)
23973            } else if let Some(range_utf16) = range_utf16 {
23974                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23975                Some(this.selection_replacement_ranges(range_utf16, cx))
23976            } else {
23977                None
23978            };
23979
23980            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23981                let newest_selection_id = this.selections.newest_anchor().id;
23982                this.selections
23983                    .all::<OffsetUtf16>(cx)
23984                    .iter()
23985                    .zip(ranges_to_replace.iter())
23986                    .find_map(|(selection, range)| {
23987                        if selection.id == newest_selection_id {
23988                            Some(
23989                                (range.start.0 as isize - selection.head().0 as isize)
23990                                    ..(range.end.0 as isize - selection.head().0 as isize),
23991                            )
23992                        } else {
23993                            None
23994                        }
23995                    })
23996            });
23997
23998            cx.emit(EditorEvent::InputHandled {
23999                utf16_range_to_replace: range_to_replace,
24000                text: text.into(),
24001            });
24002
24003            if let Some(ranges) = ranges_to_replace {
24004                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24005                    s.select_ranges(ranges)
24006                });
24007            }
24008
24009            let marked_ranges = {
24010                let snapshot = this.buffer.read(cx).read(cx);
24011                this.selections
24012                    .disjoint_anchors_arc()
24013                    .iter()
24014                    .map(|selection| {
24015                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24016                    })
24017                    .collect::<Vec<_>>()
24018            };
24019
24020            if text.is_empty() {
24021                this.unmark_text(window, cx);
24022            } else {
24023                this.highlight_text::<InputComposition>(
24024                    marked_ranges.clone(),
24025                    HighlightStyle {
24026                        underline: Some(UnderlineStyle {
24027                            thickness: px(1.),
24028                            color: None,
24029                            wavy: false,
24030                        }),
24031                        ..Default::default()
24032                    },
24033                    cx,
24034                );
24035            }
24036
24037            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24038            let use_autoclose = this.use_autoclose;
24039            let use_auto_surround = this.use_auto_surround;
24040            this.set_use_autoclose(false);
24041            this.set_use_auto_surround(false);
24042            this.handle_input(text, window, cx);
24043            this.set_use_autoclose(use_autoclose);
24044            this.set_use_auto_surround(use_auto_surround);
24045
24046            if let Some(new_selected_range) = new_selected_range_utf16 {
24047                let snapshot = this.buffer.read(cx).read(cx);
24048                let new_selected_ranges = marked_ranges
24049                    .into_iter()
24050                    .map(|marked_range| {
24051                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24052                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24053                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24054                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24055                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24056                    })
24057                    .collect::<Vec<_>>();
24058
24059                drop(snapshot);
24060                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24061                    selections.select_ranges(new_selected_ranges)
24062                });
24063            }
24064        });
24065
24066        self.ime_transaction = self.ime_transaction.or(transaction);
24067        if let Some(transaction) = self.ime_transaction {
24068            self.buffer.update(cx, |buffer, cx| {
24069                buffer.group_until_transaction(transaction, cx);
24070            });
24071        }
24072
24073        if self.text_highlights::<InputComposition>(cx).is_none() {
24074            self.ime_transaction.take();
24075        }
24076    }
24077
24078    fn bounds_for_range(
24079        &mut self,
24080        range_utf16: Range<usize>,
24081        element_bounds: gpui::Bounds<Pixels>,
24082        window: &mut Window,
24083        cx: &mut Context<Self>,
24084    ) -> Option<gpui::Bounds<Pixels>> {
24085        let text_layout_details = self.text_layout_details(window);
24086        let CharacterDimensions {
24087            em_width,
24088            em_advance,
24089            line_height,
24090        } = self.character_dimensions(window);
24091
24092        let snapshot = self.snapshot(window, cx);
24093        let scroll_position = snapshot.scroll_position();
24094        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24095
24096        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24097        let x = Pixels::from(
24098            ScrollOffset::from(
24099                snapshot.x_for_display_point(start, &text_layout_details)
24100                    + self.gutter_dimensions.full_width(),
24101            ) - scroll_left,
24102        );
24103        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24104
24105        Some(Bounds {
24106            origin: element_bounds.origin + point(x, y),
24107            size: size(em_width, line_height),
24108        })
24109    }
24110
24111    fn character_index_for_point(
24112        &mut self,
24113        point: gpui::Point<Pixels>,
24114        _window: &mut Window,
24115        _cx: &mut Context<Self>,
24116    ) -> Option<usize> {
24117        let position_map = self.last_position_map.as_ref()?;
24118        if !position_map.text_hitbox.contains(&point) {
24119            return None;
24120        }
24121        let display_point = position_map.point_for_position(point).previous_valid;
24122        let anchor = position_map
24123            .snapshot
24124            .display_point_to_anchor(display_point, Bias::Left);
24125        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24126        Some(utf16_offset.0)
24127    }
24128}
24129
24130trait SelectionExt {
24131    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24132    fn spanned_rows(
24133        &self,
24134        include_end_if_at_line_start: bool,
24135        map: &DisplaySnapshot,
24136    ) -> Range<MultiBufferRow>;
24137}
24138
24139impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24140    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24141        let start = self
24142            .start
24143            .to_point(map.buffer_snapshot())
24144            .to_display_point(map);
24145        let end = self
24146            .end
24147            .to_point(map.buffer_snapshot())
24148            .to_display_point(map);
24149        if self.reversed {
24150            end..start
24151        } else {
24152            start..end
24153        }
24154    }
24155
24156    fn spanned_rows(
24157        &self,
24158        include_end_if_at_line_start: bool,
24159        map: &DisplaySnapshot,
24160    ) -> Range<MultiBufferRow> {
24161        let start = self.start.to_point(map.buffer_snapshot());
24162        let mut end = self.end.to_point(map.buffer_snapshot());
24163        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24164            end.row -= 1;
24165        }
24166
24167        let buffer_start = map.prev_line_boundary(start).0;
24168        let buffer_end = map.next_line_boundary(end).0;
24169        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24170    }
24171}
24172
24173impl<T: InvalidationRegion> InvalidationStack<T> {
24174    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24175    where
24176        S: Clone + ToOffset,
24177    {
24178        while let Some(region) = self.last() {
24179            let all_selections_inside_invalidation_ranges =
24180                if selections.len() == region.ranges().len() {
24181                    selections
24182                        .iter()
24183                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24184                        .all(|(selection, invalidation_range)| {
24185                            let head = selection.head().to_offset(buffer);
24186                            invalidation_range.start <= head && invalidation_range.end >= head
24187                        })
24188                } else {
24189                    false
24190                };
24191
24192            if all_selections_inside_invalidation_ranges {
24193                break;
24194            } else {
24195                self.pop();
24196            }
24197        }
24198    }
24199}
24200
24201impl<T> Default for InvalidationStack<T> {
24202    fn default() -> Self {
24203        Self(Default::default())
24204    }
24205}
24206
24207impl<T> Deref for InvalidationStack<T> {
24208    type Target = Vec<T>;
24209
24210    fn deref(&self) -> &Self::Target {
24211        &self.0
24212    }
24213}
24214
24215impl<T> DerefMut for InvalidationStack<T> {
24216    fn deref_mut(&mut self) -> &mut Self::Target {
24217        &mut self.0
24218    }
24219}
24220
24221impl InvalidationRegion for SnippetState {
24222    fn ranges(&self) -> &[Range<Anchor>] {
24223        &self.ranges[self.active_index]
24224    }
24225}
24226
24227fn edit_prediction_edit_text(
24228    current_snapshot: &BufferSnapshot,
24229    edits: &[(Range<Anchor>, String)],
24230    edit_preview: &EditPreview,
24231    include_deletions: bool,
24232    cx: &App,
24233) -> HighlightedText {
24234    let edits = edits
24235        .iter()
24236        .map(|(anchor, text)| {
24237            (
24238                anchor.start.text_anchor..anchor.end.text_anchor,
24239                text.clone(),
24240            )
24241        })
24242        .collect::<Vec<_>>();
24243
24244    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24245}
24246
24247fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24248    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24249    // Just show the raw edit text with basic styling
24250    let mut text = String::new();
24251    let mut highlights = Vec::new();
24252
24253    let insertion_highlight_style = HighlightStyle {
24254        color: Some(cx.theme().colors().text),
24255        ..Default::default()
24256    };
24257
24258    for (_, edit_text) in edits {
24259        let start_offset = text.len();
24260        text.push_str(edit_text);
24261        let end_offset = text.len();
24262
24263        if start_offset < end_offset {
24264            highlights.push((start_offset..end_offset, insertion_highlight_style));
24265        }
24266    }
24267
24268    HighlightedText {
24269        text: text.into(),
24270        highlights,
24271    }
24272}
24273
24274pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24275    match severity {
24276        lsp::DiagnosticSeverity::ERROR => colors.error,
24277        lsp::DiagnosticSeverity::WARNING => colors.warning,
24278        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24279        lsp::DiagnosticSeverity::HINT => colors.info,
24280        _ => colors.ignored,
24281    }
24282}
24283
24284pub fn styled_runs_for_code_label<'a>(
24285    label: &'a CodeLabel,
24286    syntax_theme: &'a theme::SyntaxTheme,
24287) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24288    let fade_out = HighlightStyle {
24289        fade_out: Some(0.35),
24290        ..Default::default()
24291    };
24292
24293    let mut prev_end = label.filter_range.end;
24294    label
24295        .runs
24296        .iter()
24297        .enumerate()
24298        .flat_map(move |(ix, (range, highlight_id))| {
24299            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24300                style
24301            } else {
24302                return Default::default();
24303            };
24304            let muted_style = style.highlight(fade_out);
24305
24306            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24307            if range.start >= label.filter_range.end {
24308                if range.start > prev_end {
24309                    runs.push((prev_end..range.start, fade_out));
24310                }
24311                runs.push((range.clone(), muted_style));
24312            } else if range.end <= label.filter_range.end {
24313                runs.push((range.clone(), style));
24314            } else {
24315                runs.push((range.start..label.filter_range.end, style));
24316                runs.push((label.filter_range.end..range.end, muted_style));
24317            }
24318            prev_end = cmp::max(prev_end, range.end);
24319
24320            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24321                runs.push((prev_end..label.text.len(), fade_out));
24322            }
24323
24324            runs
24325        })
24326}
24327
24328pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24329    let mut prev_index = 0;
24330    let mut prev_codepoint: Option<char> = None;
24331    text.char_indices()
24332        .chain([(text.len(), '\0')])
24333        .filter_map(move |(index, codepoint)| {
24334            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24335            let is_boundary = index == text.len()
24336                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24337                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24338            if is_boundary {
24339                let chunk = &text[prev_index..index];
24340                prev_index = index;
24341                Some(chunk)
24342            } else {
24343                None
24344            }
24345        })
24346}
24347
24348pub trait RangeToAnchorExt: Sized {
24349    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24350
24351    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24352        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24353        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24354    }
24355}
24356
24357impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24358    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24359        let start_offset = self.start.to_offset(snapshot);
24360        let end_offset = self.end.to_offset(snapshot);
24361        if start_offset == end_offset {
24362            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24363        } else {
24364            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24365        }
24366    }
24367}
24368
24369pub trait RowExt {
24370    fn as_f64(&self) -> f64;
24371
24372    fn next_row(&self) -> Self;
24373
24374    fn previous_row(&self) -> Self;
24375
24376    fn minus(&self, other: Self) -> u32;
24377}
24378
24379impl RowExt for DisplayRow {
24380    fn as_f64(&self) -> f64 {
24381        self.0 as _
24382    }
24383
24384    fn next_row(&self) -> Self {
24385        Self(self.0 + 1)
24386    }
24387
24388    fn previous_row(&self) -> Self {
24389        Self(self.0.saturating_sub(1))
24390    }
24391
24392    fn minus(&self, other: Self) -> u32 {
24393        self.0 - other.0
24394    }
24395}
24396
24397impl RowExt for MultiBufferRow {
24398    fn as_f64(&self) -> f64 {
24399        self.0 as _
24400    }
24401
24402    fn next_row(&self) -> Self {
24403        Self(self.0 + 1)
24404    }
24405
24406    fn previous_row(&self) -> Self {
24407        Self(self.0.saturating_sub(1))
24408    }
24409
24410    fn minus(&self, other: Self) -> u32 {
24411        self.0 - other.0
24412    }
24413}
24414
24415trait RowRangeExt {
24416    type Row;
24417
24418    fn len(&self) -> usize;
24419
24420    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24421}
24422
24423impl RowRangeExt for Range<MultiBufferRow> {
24424    type Row = MultiBufferRow;
24425
24426    fn len(&self) -> usize {
24427        (self.end.0 - self.start.0) as usize
24428    }
24429
24430    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24431        (self.start.0..self.end.0).map(MultiBufferRow)
24432    }
24433}
24434
24435impl RowRangeExt for Range<DisplayRow> {
24436    type Row = DisplayRow;
24437
24438    fn len(&self) -> usize {
24439        (self.end.0 - self.start.0) as usize
24440    }
24441
24442    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24443        (self.start.0..self.end.0).map(DisplayRow)
24444    }
24445}
24446
24447/// If select range has more than one line, we
24448/// just point the cursor to range.start.
24449fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24450    if range.start.row == range.end.row {
24451        range
24452    } else {
24453        range.start..range.start
24454    }
24455}
24456pub struct KillRing(ClipboardItem);
24457impl Global for KillRing {}
24458
24459const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24460
24461enum BreakpointPromptEditAction {
24462    Log,
24463    Condition,
24464    HitCondition,
24465}
24466
24467struct BreakpointPromptEditor {
24468    pub(crate) prompt: Entity<Editor>,
24469    editor: WeakEntity<Editor>,
24470    breakpoint_anchor: Anchor,
24471    breakpoint: Breakpoint,
24472    edit_action: BreakpointPromptEditAction,
24473    block_ids: HashSet<CustomBlockId>,
24474    editor_margins: Arc<Mutex<EditorMargins>>,
24475    _subscriptions: Vec<Subscription>,
24476}
24477
24478impl BreakpointPromptEditor {
24479    const MAX_LINES: u8 = 4;
24480
24481    fn new(
24482        editor: WeakEntity<Editor>,
24483        breakpoint_anchor: Anchor,
24484        breakpoint: Breakpoint,
24485        edit_action: BreakpointPromptEditAction,
24486        window: &mut Window,
24487        cx: &mut Context<Self>,
24488    ) -> Self {
24489        let base_text = match edit_action {
24490            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24491            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24492            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24493        }
24494        .map(|msg| msg.to_string())
24495        .unwrap_or_default();
24496
24497        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24498        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24499
24500        let prompt = cx.new(|cx| {
24501            let mut prompt = Editor::new(
24502                EditorMode::AutoHeight {
24503                    min_lines: 1,
24504                    max_lines: Some(Self::MAX_LINES as usize),
24505                },
24506                buffer,
24507                None,
24508                window,
24509                cx,
24510            );
24511            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24512            prompt.set_show_cursor_when_unfocused(false, cx);
24513            prompt.set_placeholder_text(
24514                match edit_action {
24515                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24516                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24517                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24518                },
24519                window,
24520                cx,
24521            );
24522
24523            prompt
24524        });
24525
24526        Self {
24527            prompt,
24528            editor,
24529            breakpoint_anchor,
24530            breakpoint,
24531            edit_action,
24532            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24533            block_ids: Default::default(),
24534            _subscriptions: vec![],
24535        }
24536    }
24537
24538    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24539        self.block_ids.extend(block_ids)
24540    }
24541
24542    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24543        if let Some(editor) = self.editor.upgrade() {
24544            let message = self
24545                .prompt
24546                .read(cx)
24547                .buffer
24548                .read(cx)
24549                .as_singleton()
24550                .expect("A multi buffer in breakpoint prompt isn't possible")
24551                .read(cx)
24552                .as_rope()
24553                .to_string();
24554
24555            editor.update(cx, |editor, cx| {
24556                editor.edit_breakpoint_at_anchor(
24557                    self.breakpoint_anchor,
24558                    self.breakpoint.clone(),
24559                    match self.edit_action {
24560                        BreakpointPromptEditAction::Log => {
24561                            BreakpointEditAction::EditLogMessage(message.into())
24562                        }
24563                        BreakpointPromptEditAction::Condition => {
24564                            BreakpointEditAction::EditCondition(message.into())
24565                        }
24566                        BreakpointPromptEditAction::HitCondition => {
24567                            BreakpointEditAction::EditHitCondition(message.into())
24568                        }
24569                    },
24570                    cx,
24571                );
24572
24573                editor.remove_blocks(self.block_ids.clone(), None, cx);
24574                cx.focus_self(window);
24575            });
24576        }
24577    }
24578
24579    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24580        self.editor
24581            .update(cx, |editor, cx| {
24582                editor.remove_blocks(self.block_ids.clone(), None, cx);
24583                window.focus(&editor.focus_handle);
24584            })
24585            .log_err();
24586    }
24587
24588    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24589        let settings = ThemeSettings::get_global(cx);
24590        let text_style = TextStyle {
24591            color: if self.prompt.read(cx).read_only(cx) {
24592                cx.theme().colors().text_disabled
24593            } else {
24594                cx.theme().colors().text
24595            },
24596            font_family: settings.buffer_font.family.clone(),
24597            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24598            font_size: settings.buffer_font_size(cx).into(),
24599            font_weight: settings.buffer_font.weight,
24600            line_height: relative(settings.buffer_line_height.value()),
24601            ..Default::default()
24602        };
24603        EditorElement::new(
24604            &self.prompt,
24605            EditorStyle {
24606                background: cx.theme().colors().editor_background,
24607                local_player: cx.theme().players().local(),
24608                text: text_style,
24609                ..Default::default()
24610            },
24611        )
24612    }
24613}
24614
24615impl Render for BreakpointPromptEditor {
24616    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24617        let editor_margins = *self.editor_margins.lock();
24618        let gutter_dimensions = editor_margins.gutter;
24619        h_flex()
24620            .key_context("Editor")
24621            .bg(cx.theme().colors().editor_background)
24622            .border_y_1()
24623            .border_color(cx.theme().status().info_border)
24624            .size_full()
24625            .py(window.line_height() / 2.5)
24626            .on_action(cx.listener(Self::confirm))
24627            .on_action(cx.listener(Self::cancel))
24628            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24629            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24630    }
24631}
24632
24633impl Focusable for BreakpointPromptEditor {
24634    fn focus_handle(&self, cx: &App) -> FocusHandle {
24635        self.prompt.focus_handle(cx)
24636    }
24637}
24638
24639fn all_edits_insertions_or_deletions(
24640    edits: &Vec<(Range<Anchor>, String)>,
24641    snapshot: &MultiBufferSnapshot,
24642) -> bool {
24643    let mut all_insertions = true;
24644    let mut all_deletions = true;
24645
24646    for (range, new_text) in edits.iter() {
24647        let range_is_empty = range.to_offset(snapshot).is_empty();
24648        let text_is_empty = new_text.is_empty();
24649
24650        if range_is_empty != text_is_empty {
24651            if range_is_empty {
24652                all_deletions = false;
24653            } else {
24654                all_insertions = false;
24655            }
24656        } else {
24657            return false;
24658        }
24659
24660        if !all_insertions && !all_deletions {
24661            return false;
24662        }
24663    }
24664    all_insertions || all_deletions
24665}
24666
24667struct MissingEditPredictionKeybindingTooltip;
24668
24669impl Render for MissingEditPredictionKeybindingTooltip {
24670    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24671        ui::tooltip_container(cx, |container, cx| {
24672            container
24673                .flex_shrink_0()
24674                .max_w_80()
24675                .min_h(rems_from_px(124.))
24676                .justify_between()
24677                .child(
24678                    v_flex()
24679                        .flex_1()
24680                        .text_ui_sm(cx)
24681                        .child(Label::new("Conflict with Accept Keybinding"))
24682                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24683                )
24684                .child(
24685                    h_flex()
24686                        .pb_1()
24687                        .gap_1()
24688                        .items_end()
24689                        .w_full()
24690                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24691                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24692                        }))
24693                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24694                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24695                        })),
24696                )
24697        })
24698    }
24699}
24700
24701#[derive(Debug, Clone, Copy, PartialEq)]
24702pub struct LineHighlight {
24703    pub background: Background,
24704    pub border: Option<gpui::Hsla>,
24705    pub include_gutter: bool,
24706    pub type_id: Option<TypeId>,
24707}
24708
24709struct LineManipulationResult {
24710    pub new_text: String,
24711    pub line_count_before: usize,
24712    pub line_count_after: usize,
24713}
24714
24715fn render_diff_hunk_controls(
24716    row: u32,
24717    status: &DiffHunkStatus,
24718    hunk_range: Range<Anchor>,
24719    is_created_file: bool,
24720    line_height: Pixels,
24721    editor: &Entity<Editor>,
24722    _window: &mut Window,
24723    cx: &mut App,
24724) -> AnyElement {
24725    h_flex()
24726        .h(line_height)
24727        .mr_1()
24728        .gap_1()
24729        .px_0p5()
24730        .pb_1()
24731        .border_x_1()
24732        .border_b_1()
24733        .border_color(cx.theme().colors().border_variant)
24734        .rounded_b_lg()
24735        .bg(cx.theme().colors().editor_background)
24736        .gap_1()
24737        .block_mouse_except_scroll()
24738        .shadow_md()
24739        .child(if status.has_secondary_hunk() {
24740            Button::new(("stage", row as u64), "Stage")
24741                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24742                .tooltip({
24743                    let focus_handle = editor.focus_handle(cx);
24744                    move |window, cx| {
24745                        Tooltip::for_action_in(
24746                            "Stage Hunk",
24747                            &::git::ToggleStaged,
24748                            &focus_handle,
24749                            window,
24750                            cx,
24751                        )
24752                    }
24753                })
24754                .on_click({
24755                    let editor = editor.clone();
24756                    move |_event, _window, cx| {
24757                        editor.update(cx, |editor, cx| {
24758                            editor.stage_or_unstage_diff_hunks(
24759                                true,
24760                                vec![hunk_range.start..hunk_range.start],
24761                                cx,
24762                            );
24763                        });
24764                    }
24765                })
24766        } else {
24767            Button::new(("unstage", row as u64), "Unstage")
24768                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24769                .tooltip({
24770                    let focus_handle = editor.focus_handle(cx);
24771                    move |window, cx| {
24772                        Tooltip::for_action_in(
24773                            "Unstage Hunk",
24774                            &::git::ToggleStaged,
24775                            &focus_handle,
24776                            window,
24777                            cx,
24778                        )
24779                    }
24780                })
24781                .on_click({
24782                    let editor = editor.clone();
24783                    move |_event, _window, cx| {
24784                        editor.update(cx, |editor, cx| {
24785                            editor.stage_or_unstage_diff_hunks(
24786                                false,
24787                                vec![hunk_range.start..hunk_range.start],
24788                                cx,
24789                            );
24790                        });
24791                    }
24792                })
24793        })
24794        .child(
24795            Button::new(("restore", row as u64), "Restore")
24796                .tooltip({
24797                    let focus_handle = editor.focus_handle(cx);
24798                    move |window, cx| {
24799                        Tooltip::for_action_in(
24800                            "Restore Hunk",
24801                            &::git::Restore,
24802                            &focus_handle,
24803                            window,
24804                            cx,
24805                        )
24806                    }
24807                })
24808                .on_click({
24809                    let editor = editor.clone();
24810                    move |_event, window, cx| {
24811                        editor.update(cx, |editor, cx| {
24812                            let snapshot = editor.snapshot(window, cx);
24813                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24814                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24815                        });
24816                    }
24817                })
24818                .disabled(is_created_file),
24819        )
24820        .when(
24821            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24822            |el| {
24823                el.child(
24824                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24825                        .shape(IconButtonShape::Square)
24826                        .icon_size(IconSize::Small)
24827                        // .disabled(!has_multiple_hunks)
24828                        .tooltip({
24829                            let focus_handle = editor.focus_handle(cx);
24830                            move |window, cx| {
24831                                Tooltip::for_action_in(
24832                                    "Next Hunk",
24833                                    &GoToHunk,
24834                                    &focus_handle,
24835                                    window,
24836                                    cx,
24837                                )
24838                            }
24839                        })
24840                        .on_click({
24841                            let editor = editor.clone();
24842                            move |_event, window, cx| {
24843                                editor.update(cx, |editor, cx| {
24844                                    let snapshot = editor.snapshot(window, cx);
24845                                    let position =
24846                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24847                                    editor.go_to_hunk_before_or_after_position(
24848                                        &snapshot,
24849                                        position,
24850                                        Direction::Next,
24851                                        window,
24852                                        cx,
24853                                    );
24854                                    editor.expand_selected_diff_hunks(cx);
24855                                });
24856                            }
24857                        }),
24858                )
24859                .child(
24860                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24861                        .shape(IconButtonShape::Square)
24862                        .icon_size(IconSize::Small)
24863                        // .disabled(!has_multiple_hunks)
24864                        .tooltip({
24865                            let focus_handle = editor.focus_handle(cx);
24866                            move |window, cx| {
24867                                Tooltip::for_action_in(
24868                                    "Previous Hunk",
24869                                    &GoToPreviousHunk,
24870                                    &focus_handle,
24871                                    window,
24872                                    cx,
24873                                )
24874                            }
24875                        })
24876                        .on_click({
24877                            let editor = editor.clone();
24878                            move |_event, window, cx| {
24879                                editor.update(cx, |editor, cx| {
24880                                    let snapshot = editor.snapshot(window, cx);
24881                                    let point =
24882                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24883                                    editor.go_to_hunk_before_or_after_position(
24884                                        &snapshot,
24885                                        point,
24886                                        Direction::Prev,
24887                                        window,
24888                                        cx,
24889                                    );
24890                                    editor.expand_selected_diff_hunks(cx);
24891                                });
24892                            }
24893                        }),
24894                )
24895            },
24896        )
24897        .into_any_element()
24898}
24899
24900pub fn multibuffer_context_lines(cx: &App) -> u32 {
24901    EditorSettings::try_get(cx)
24902        .map(|settings| settings.excerpt_context_lines)
24903        .unwrap_or(2)
24904        .min(32)
24905}